In the C language, object-oriented abstraction can be implemented using structures and functions. In C, a pointer to a structure can be defined without disclosing the elements of the structure. For example, in the header file Shape.h we define opaque type

`typedef const struct __Shape * ShapeRef;`

This declares a new type, `ShapeRef`, which is a pointer to a hidden structure `__Shape`. While the messages we can send to (or functions we can call with) this structure pointer are defined in a C header file, i.e. Shape.h, we are not allowed to see nor access directly the elements of this structure.

You can read more about Opaque data types and Opaque pointers at Wikipedia. You can also learn more about Opaque types at Apple.

You may have noticed in the example on Opaque Types that the pointer was defined using the `const` keyword. The keyword `const` means that the contents of `__Shape` structure cannot be modified after it is created. This makes Shape an **immutable** type. This means that while we can define functions that reveal the internal state (i.e., structure elements) of Shape, we cannot define functions that change its internal state. Only by eliminating the keyword `const` in the type definition would we be able to define functions to change the internal state of the type. A type whose internal state can be modified after creation is called a **mutable** type. Thus, in the header file Shape.h we also define the opaque type

`typedef struct __Shape * MutableShapeRef;`

What are the advantages of an immutable type? Let's say you want to use an instance of type A as a variable inside type B. You decide to do this by placing a copy of the pointer for the instance of A inside B. Unbeknownst to you, however, another type, let's call it C, also has a copy of the pointer for the same instance of A. If A was mutable, then type C could change the value of A, and, in turn, change the instance variable A inside B, without B knowing what happened. There are two ways to handle this problem. If A is mutable, then type B has no choice but to make its own personal copy of the A instance. Depending on the size of A, this could be a memory and time consuming process. On the other hand, if A is immutable, then B can safely (and rapidly) copy only the pointer for A. As you might imagine, immutable types are highly useful in concurrent programs. General advice: don't define an type as mutable unless you really need it.

Read more about Mutable and Immutable types at Wikipedia.

Now, looking inside the source Shape.c, we find the structure

```
struct __Shape {
// Shape Type attributes - order of declaration is essential
float xPosition;
float yPosition;
float orientation;
};
```

Creation and Destruction of the Shape Type is handled with these function:

```
￼￼static struct __Shape *ShapeAllocate()
{
struct __Shape *theShape = malloc(sizeof(struct __Shape));
if(NULL == theShape) return NULL;
return theShape;
}
ShapeRef ShapeCreate(float xPosition, float yPosition, float orientation)
{
struct __Shape *newShape = ShapeAllocate();
if(NULL == newShape) return NULL;
newShape->xPosition = xPosition;
newShape->yPosition = yPosition;
newShape->orientation = orientation;
return newShape;
}
void ShapeFinalize(ShapeRef theShape)
{
if(NULL == theShape) return;
free((void *)theShape);
}
```

Comparison and Accessors are handled with these functions:

```
bool ShapeEqual(ShapeRef theShape1, ShapeRef theShape2)
{
if(NULL == theShape1 || NULL == theShape2) return false;
if(theShape1 == theShape2) return true;
if(theShape1->xPosition != theShape2->xPosition) return false;
if(theShape1->yPosition != theShape2->yPosition) return false;
if(theShape1->orientation != theShape2->orientation) return false;
return true;
}
float ShapeGetXPosition(ShapeRef theShape)
{
if(NULL == theShape) return nan(NULL);
return theShape->xPosition;
}
void ShapeSetXPosition(MutableShapeRef theShape, float xPosition) {
if(NULL == theShape) return;
theShape->xPosition = xPosition;
}
```

A shape can be translated and rotated. These methods are handled with these functions:

```
void ShapeTranslate(MutableShapeRef theShape, float xTranslation, float yTranslation)
{
if(NULL == theShape) return;
theShape->xPosition += xTranslation;
theShape->yPosition += yTranslation;
}
void ShapeRotate(MutableShapeRef theShape, float angle)
{
if(NULL == theShape) return;
theShape->orientation += angle;
}
```

```
MutableShapeRef shape = ShapeCreateMutable(0.0, 0.0, 0.0);
ShapeShow(shape);
ShapeTranslate(shape, 10.0, 20.0);
ShapeRotate(shape, 180.);
ShapeShow(shape);
ShapeFinalize(shape);
```

￼
Let's examine how we can define a Square type that inherits from Shape. In source code we define the structure

```
struct __Square {
// Shape Type attributes - order of declaration is essential
float xPosition;
float yPosition;
float orientation;
// Square Type attributes
float width;
};
```

For this inheritance trick to work it is essential that the order of instance variable declarations be identical to those inside the Shape structure. Any additional instance variables must go after the variables matching Shape's structure.

In the header file we define the opaque types

```
typedef const struct __Square * SquareRef;
typedef struct __Square * MutableSquareRef;
```

Creation and Destruction of the Square Type is handled with these function:

```
static struct __Square *SquareAllocate()
{
struct __Square *theSquare = malloc(sizeof(struct __Square)); if(NULL == theSquare) return NULL;
return theSquare;
}
SquareRef SquareCreate(float xPosition, float yPosition, float orientation, float width)
{
struct __Square *newSquare = SquareAllocate();
if(NULL == newSquare) return NULL;
newSquare->xPosition = xPosition;
newSquare->yPosition = yPosition;
newSquare->orientation = orientation;
newSquare->width = width;
return newSquare;
}
void SquareFinalize(SquareRef theSquare)
{
if(NULL == theSquare) return;
free((void *)theSquare);
}
```

Comparison and Accessors are handled with these functions:

```
bool SquareEqual(SquareRef theSquare1, SquareRef theSquare2)
{
if(!ShapeEqual((ShapeRef) theSquare1, (ShapeRef) theSquare2)) return false;
if(theSquare1->width != theSquare2->width) return false;
return true;
}
float SquareGetXPosition(SquareRef theSquare)
{
return ShapeGetXPosition((ShapeRef) theSquare);
}
float SquareGetWidth(SquareRef theSquare)
{
if(NULL == theSquare) return nan(NULL);
return theSquare->width;
}
void SquareSetXPosition(MutableSquareRef theSquare, float xPosition)
{
ShapeSetXPosition((MutableShapeRef) theSquare, xPosition);
}
void SquareSetWidth(MutableSquareRef theSquare, float width)
{
if(NULL == theSquare) return;
theSquare->width = width;
}
```

Notice how we type cast a Square into a Shape before calling Shape methods.

```
MutableSquareRef square = MutableSquareCreate(0.0, 0.0, 0.0, 10.0);
ShapeShow((ShapeRef) square);
SquareShow(square);
ShapeTranslate((MutableShapeRef) square, 10.0, 20.0);
ShapeRotate((MutableShapeRef) square, 180.);
SquareShow(square);
SquareFinalize(square);
```

Source code used in this section:

Shape.c Shape.h Square.c Square.h main.c

In the last section we examined how Opaque types in C can be adapted to follow some Object Oriented Design Patterns. It is a sensible approach but it still lacks memory management, collections, strings, and many other useful object-oriented design features. To continue on our path towards a more complete approach let's look how we can introduce retain count memory management.

When an type is no longer needed it should be deallocated and its memory freed. But how will a type know when it's no longer needed? Type A may hold a reference (pointer) to type B, but how does type A know that type B still exists? For example, type B could have initially been created to be part of type C. If type C gets destroyed along with all it's constituent objects and type A doesn't know, then type A could end up sending a message to (calling a function with) a non-existent type B, and crash the program.

The solution we adopt to solve this problem is called reference counting. When a type wants to hold a reference to another type it calls that type's retain function. Every time an type's retain function is called, it increments its internal retainCount variable. Conversely, when an type no longer needs to hold a reference to a type it calls that type's release function. Every time an type's release function is called, it decrements its internal retainCount variable. When a type's retainCount hits zero, then the type self destructs. That is, it would call the release function of any types it had retained, and then deallocate itself.

With this in mind, we follow the conventions below.

- if you create an type (either directly or by making a copy of another type—see “The Create Rule”), you own it. We will explicitly use the word
Create

orCopy

in the name of any function that creates and returns a type with a retain count of 1. - if you get an type from somewhere else, you do not own it. If you want to prevent it being disposed of, you must add yourself as an owner (using a retain method).
- if you are an owner of an type, you must relinquish ownership when you have finished using it (using a release method).

Read more about Reference counting at Wikipedia and at Apple.

We begin by creating a fundamental opaque type called KFType, from which all other types will inherit. In KFType source code define structure

```
struct __KFType {
u_int32_t retainCount;
void (*finalize)(void *);
bool (*equal)(void *, void *);
};
```

In KFType header define opaque type

`typedef struct __KFType * KFTypeRef;`

KFType Methods
```
bool KFTypeEqual(KFTypeRef theType1, KFTypeRef theType2)
{
return theType1->equal(theType1,theType2);
}
void KFRelease(KFTypeRef theType)
{
if(NULL==theType) return;
if(theType->retainCount == 1) {
theType->finalize(theType); return;
}
theType->retainCount--;
return;
}
KFTypeRef KFRetain(KFTypeRef theType)
{
if(NULL==theType) return NULL;
theType->retainCount++;
return theType;
}
```

Now we can define KFShape to inherit from KFType
```
struct __KFShape {
u_int32_t retainCount;
void (*finalize)(void *);
bool (*equal)(void *, void *);
// Shape Type attributes
float xPosition;
float yPosition;
float orientation;
};
static struct __KFShape *KFShapeAllocate()
{
struct __KFShape *theShape = malloc(sizeof(struct __KFShape));
if(NULL == theShape) return NULL;
theShape->retainCount = 1;
theShape->finalize = KTShapeFinalize;
theShape->equal = KFShapeEqual;
return theShape;
}
```

```
KFMutableShapeRef shape = KFShapeCreateMutable(0.0, 0.0, 0.0);
KFShapeShow(shape);
KFShapeTranslate(shape, 10.0, 20.0);
KFShapeRotate(shape, 180.);
KFShapeShow(shape);
KFRelease((KFTypeRef) shape);
```

Source code used in this section:

KFType.c KFType.h KFShape.c KFShape.h main.c

At this point, if you know anything about object-oriented programming, you are thinking ￼Yeah, but you would still have to create types like KFSet, KFArray, KFDictionary, KFString, etc.

Well, that is true. The good news, however, is that Apple has done all that for us. Starting with their fundamental CFType, Apple has built CFSet, CFArray, CFDictionary, CFString, and many, many other wonderful types. Reference counting is also the approach employed in Core Foundation.

Even more wonderful is that Apple's Core Foundation framework is open source and a version called Core Foundation Lite can be used to write cross-platform applications for Mac OS X, Linux, and Windows (via Cygwin).

This is easy if your instance variables (ivars) can be readily defined with other Core Foundation Types, e.g., CFNumber, CFString, etc. but adds overhead particularly when you have to wraps many int’s and float’s into CFNumbers.

Alternatively, you can create your own type that inherits from CFType and takes full advantage of the Core Foundation library. Inside the source for our Shape is a structure that inherits from CFType.

```
#include <CoreFoundation/CoreFoundation.h>
#include "CFRuntime.h"
struct __CFShape {
CFRuntimeBase _base;
// Shape Type attributes
float xPosition;
float yPosition;
float orientation;
};
```

Notice that the first line of every CFType structure is `CFRuntimeBase _base;`. This is defined in the file CFRuntime.h

, which can be found at the bottom of this page. This file needs to be included in your project if you plan to create your own CFType.

Inside the header file for CFShape we define the types.

```
typedef const struct __CFShape * CFShapeRef;
typedef struct __CFShape * CFMutableShapeRef;
```

Also inside the source we use the following code for allocating and creating a CFShape.

```
// Static variable that gets assigned a unique value when the first CFShape is created.
static CFTypeID _kCFShapeID = _kCFRuntimeNotATypeID;
// CFRuntimeClass variable defining our CFShape type for Core Foundation.
static CFRuntimeClass _kCFShapeClass = {
0,
"CFShape",
NULL,
NULL,
CFShapeFinalize,
CFShapeEqual,
NULL,
NULL,
CFShapeCopyDebugDesc};
// Allocate CFShape.
static struct __CFShape *CFShapeAllocate()
{
// First time a CFShape is allocated, so we need to register the type with Core Foundation
if(_kCFShapeID ==_kCFRuntimeNotATypeID) {
_kCFShapeID = _CFRuntimeRegisterClass((const CFRuntimeClass * const)&_kCFShapeClass);
}
// Allocate a CFShape
struct __CFShape *theShape;
uint32_t extra = sizeof(struct __CFShape) - sizeof(CFRuntimeBase);
theShape = (struct __CFShape *)_CFRuntimeCreateInstance(kCFAllocatorDefault, _kCFShapeID, extra, NULL);
if (NULL == theShape) return NULL;
return theShape;
}
CFShapeRef CFShapeCreate(float xPosition, float yPosition, float orientation)
{
struct __CFShape *newShape = CFShapeAllocate();
if(NULL == newShape) return NULL;
newShape->xPosition = xPosition;
newShape->yPosition = yPosition;
newShape->orientation = orientation;
return newShape;
}
CFMutableShapeRef CFShapeCreateMutable(float xPosition, float yPosition, float orientation)
{
return (CFMutableShapeRef) CFShapeCreate(xPosition, yPosition, orientation);
}
```

Here's an example to match our previous examples.

```
CFMutableShapeRef shape = CFShapeCreateMutable(0.0, 0.0, 0.0);
CFShapeShow(shape);
CFShapeTranslate(shape, 10.0, 20.0);
CFShapeRotate(shape, 180.);
CFShapeShow(shape);
CFRelease(shape);
```

Things get more exciting, however, when you bring all the rest of Core Foundation's various types to bear in your code. Here's an example using CFArray.

```
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for(float orientation = 0.0; orientation <360.; orientation += 45.0) {
CFMutableShapeRef shape = CFShapeCreateMutable(0.0, 0.0, orientation);
CFShapeShow(shape);
CFArrayAppendValue(array, shape);
CFRelease(shape);
}
printf("\n\n");
CFIndex count = CFArrayGetCount(array);
for(CFIndex index = 0; index< count; index++) {
CFMutableShapeRef shape = (CFMutableShapeRef) CFArrayGetValueAtIndex(array, index);
CFShapeShow(shape);
}
CFRelease(array);
```

Just wait, it gets even better. You can even use your CFType as an object in Objective-C. Here's a translation of the code above into objective C.

```
@autoreleasepool {
NSMutableArray *array = [[NSMutableArray alloc] init];
for(float orientation = 0.0; orientation <360.; orientation += 45.0) {
CFMutableShapeRef shape = CFShapeCreateMutable(0.0, 0.0, orientation);
CFShapeShow(shape);
NSLog(@"retain count is %ld",[(id) shape retainCount]);
[array addObject:(id) shape];
NSLog(@"retain count is %ld",[(id) shape retainCount]);
[(id) shape retain];
NSLog(@"retain count is %ld",[(id) shape retainCount]);
[(id) shape release];
CFRelease(shape);
}
printf("\n\n");
NSUInteger count = [array count];
for(NSUInteger index = 0; index< count; index++) {
CFMutableShapeRef shape = (CFMutableShapeRef) [array objectAtIndex:index];
CFShapeShow(shape);
}
[array release];
}
```

While we still create our shape with the C method, we can put our shape into an NSArray and get it out with no problems. We can retain and release our shape as if it was an objective C object. And our shape even gets released when the array containing it is released.

One final note: I would suggest that you don't use CF

as the first two characters of the name of your own CFTypes. Leave those for Apple.

Source code used in this section:

CFRuntime.h CFShape.c CFShape.h main.c main.m

PhySy is written in C using object-oriented design concepts. This design is modeled after Apple's Core Foundation framework. PhySy Foundation is also built on top of the Core Foundation framework.

The PhySy Foundation framework provides support for the SI Units of quantities in the physical sciences.

An important characteristic of physical quantities is that any given physical quantity can be derived from other physical quantities through physical laws. For example, the physical quantity of speed is calculated as a ratio of distance traveled to time elapsed. The volume of a box is calculated as the product of three quantities of length: i.e., height, width, and depth of the box. Any physical quantity can always be related back through physical laws to a smaller set of reference physical quantities. This idea was originally proposed by Joseph Fourier in his book *Théorie analytique de la chaleur* (The Analytic Theory of heat). In fact, as the laws of physics become unified it has been argued that this smaller set can be reduced to simply the Planck length and the speed of light. At the level of theory employed by most scientists and engineers, however, there is a practical agreement that seven physical quantities should serve as fundamental reference quantities from which all other physical quantities can be derived. These reference quantities are (1) length, (2) mass, (3) time, (4) electric current, (5) thermodynamic temperature, (6) amount of substance, and (7) luminous intensity.

In the next parts we examine the three important types in PhySy Foundation: PSScalar, PSUnit, and PSDimensionality. Ultimately, programmers will have more significant interactions with a type like PSScalar than PSUnit, and even less than with PSDimensionality. Therefore, we begin this tutorial with the PSScalar type.

PSScalar represent a scalar physical quantity, and has two essential attributes: a numerical value and a unit. It supports four element types: float, double, float complex, and double complex.

One simple method for creating a PSScalar is to parse a string input using the method shown below:

```
PSScalarRef acceleration = PSScalarCreateWithCFString(CFSTR("9.8 m/s^2"));
PSScalarShow(acceleration);
```

The `CFSTR()` method is a Core Foundation macro for creating constant compile-time strings. The output of this code is the value of the scalar.

```
9.8 m/s^2
```

We can define another scalar and divide by our previous scalar,

```
PSUnitRef newtons = PSUnitFindWithName(CFSTR("newtons"));
PSScalarRef force = PSScalarCreateWithDouble(500,newtons);
PSScalarRef mass = PSScalarCreateByDividing(force, acceleration);
PSScalarShow(mass);
```

in code that displays
`51.02041 kg`

Unit conversions are straightforward. One approach, given below,

```
PSUnitRef grams = PSUnitFindWithName(CFSTR("grams"));
PSScalarConvertToUnit((PSMutableScalarRef) mass, grams);
PSScalarShow(mass);
```

displays
`51020.41 g`

Let's consider a problem familiar to chemistry students.

What pressure in atmospheres does 0.078 moles of hydrogen exert on the walls of a 42.0 mL container at 25.0 °C?Using the ideal gas equation of state, $p V = n R T$, we identify the variables

and solve for the pressure: $ p = n R T/V$. The solution can be coded as follows.

```
PSScalarRef n = PSScalarCreateWithCFString(CFSTR("0.078 mol"));
PSScalarRef T = PSScalarCreateWithCFString(CFSTR("298.15 K"));
PSScalarRef V = PSScalarCreateWithCFString(CFSTR("42.0 mL"));
PSScalarRef R = PSScalarCreateWithCFString(CFSTR("8.314510 J/(K*mol)"));
PSMutableScalarRef p = (PSMutableScalarRef) PSScalarCreateByMultiplying(n, R);
PSScalarMultiply(p, T);
PSScalarDivide(p, V);
PSScalarShow(p);
CFRelease(n);
CFRelease(T);
CFRelease(V);
CFRelease(R);
CFRelease(p);
```

The output from this code is
`4603803.67339444 Pa`

Alternatively, the entire calculation can be done inside the string input,

```
PSScalarRef p = PSScalarCreateWithCFString(CFSTR("0.078 mol * 8.314510 J/(K*mol) * 298.15 K/(42.0 mL)"));
PSScalarShow(p);
```

with identical output.
`4603803.67339444 Pa`

Let's not forget that the problem requested the final pressure in units of atmospheres. This can be readily obtained with the code below,

```
PSUnitRef atmospheres = PSUnitFindWithName(CFSTR("atmospheres"));
PSScalarConvertToUnit((PSMutableScalarRef) p, atmospheres);
PSScalarShow(p);
```

which to get the answer in the correct units.
`45.43574381963646 atm`

See the full API of PSScalar here.

PSScalar is also a concrete subtype of **PSQuantity**, whose full API can be found here. For example, if you want to get the unit in a PSScalar you can call the parent type method, PSQuantityGetUnit, according to

```
PSUnitRef unit = PSQuantityGetUnit( (PSQuantityRef) p);
PSScalarShow(unit);
```

which displays the units of p.
`atm`

Another concrete subtype of PSQuantity is **PSBlock**, which represents a block of physical quantities with the same unit. The API for PSBlock can be found here.

Inherent in the measurement of any physical quantity is a comparison to a previous measurement. What is most useful is the ratio of the new measurement to a previous measurement. For example, an ancient scientist might have used a cubit to measure the ratio of large tree trunk's circumference to its diameter. Around 3000 B.C.E., a cubit was decreed to be the length of a forearm and hand. So, a scientist could make a string of 1 cubit in length using the distance from the back of her elbow to the tip of her middle finger, and then use the string to measured the ratio \begin{equation} \frac{l_\text{circumference}} {l_\text{diameter}} = 3.14. \end{equation} While another scientist with longer arms might have cut a longer string to be a cubit, the procedure for finding the ratio of large tree trunk's circumference to its diameter will be the same, and the result is independent of the absolute length of the string used, i.e., independent of the units of length used.

We will represent a physical quantity, $q$, using the notation \begin{equation} q = \{ q \} \cdot [q], \end{equation} where $\{ q \}$ is the numerical value and $[q]$ is the reference unit.

The **coherent SI base (reference) units** form a set of seven units, and are given below:

Base Dimension | Name | Plural Name | Symbol |
---|---|---|---|

length | meter | meters | m |

mass | kilogram | kilograms | kg |

time | second | seconds | s |

electric current | ampere | ampere | A |

thermodynamic temperature | kelvin | kelvin | K |

amount of substance | mole | moles | mol |

luminous intensity | candela | candelas | cd |

The *coherent SI base (reference) units* form a set of seven units, described in table above and given by the symbols
\begin{equation}
[q]_\text{CBU} \in [Q]_\text{CBU} = \left\{ \mbox{m}, \mbox{kg}, \mbox{s}, \mbox{A}, \mbox{K}, \mbox{mol}, \mbox{cd} \right\}.
\end{equation}

A minor complication in designing our model is that the coherent base unit for mass in SI Units is defined as the kilogram and not the gram. For this reason, we define a set of seven base root units, \begin{equation} [q]_\text{BRU} \in [Q]_\text{BRU} = \left\{ \mbox{m}, \mbox{g}, \mbox{s}, \mbox{A}, \mbox{K}, \mbox{mol}, \mbox{cd} \right\}. \end{equation} with names and symbols shown in the table below.

Base Dimension | Name | Plural Name | Symbol |
---|---|---|---|

length | meter | meters | m |

mass | gram | gram | g |

time | second | seconds | s |

electric current | ampere | ampere | A |

thermodynamic temperature | kelvin | kelvin | K |

amount of substance | mole | moles | mol |

luminous intensity | candela | candelas | cd |

SI Prefix Name | x, SI Prefix Symbol | factor | SI Prefix Name | x, SI Prefix Symbol | factor |
---|---|---|---|---|---|

yotta | Y | $10^{24}$ | yocto | y | $10^{-24}$ |

zetta | Z | $10^{21}$ | zepto | z | $10^{-21}$ |

exa | E | $10^{18}$ | atto | a | $10^{-18}$ |

peta | P | $10^{15}$ | femto | f | $10^{-15}$ |

tera | T | $10^{12}$ | pico | p | $10^{-12}$ |

giga | G | $10^{9}$ | nano | n | $10^{-9}$ |

mega | M | $10^{6}$ | micro | $\mu$ | $10^{-6}$ |

kilo | k | $10^{3}$ | milli | m | $10^{-3}$ |

hecto | h | $10^{2}$ | centi | c | $10^{-2}$ |

deca | da | $10^{1}$ | deci | d | $10^{-1}$ |

In PhySy, one can obtain any of these units its symbol and the function

`PSUnitRef massUnit = PSUnitForSymbol(CFSTR("kg"),NULL);`

Here `CFSTR(const char *cStr)` is a Core Foundation function that creates an immutable string from a constant compile-time string. The second argument, set to NULL in this case, is a pointer to a double holds a multiplier, if needed, for converting between the unit whose symbol is passed in the string argument and the unit returned. In cases such as this one, where a multiplier is clearly not needed, then a NULL pointer can be safely passed to the function. Examples where a multiplier will be necessary are given later in this section.

**Coherent derived SI units** are an infinite set defined as the products of powers of **coherent SI base units** for all positive and negative integer values of the exponents.

`PSUnitRef forceUnit = PSUnitForSymbol(CFSTR("kg*m/s^2"),NULL);`

```
PSDimensionalityRef pressureDimensionality = PSDimensionalityForQuantity(CFSTR("pressure"));
PSUnitRef pressureUnit = PSUnitCoherentSIUnitForDimensionality(pressureDimensionality);
```

**Derived SI units** are an infinite set defined as the products of powers of **SI base units** for all positive and negative integer values of the exponents.

`PSUnitRef forceUnit = PSUnitForSymbol(CFSTR("g*m/s^2"),NULL);`

`PSUnitRef forceUnit = PSUnitForSymbol(CFSTR("mg*cm/ps^2"),NULL);`

While all units in the set $[Q]_\text{DU}$ have unique derived symbols and names, it should be noted that some are functionally equivalent. For example, a derived physical quantity such as speed in units of $[\text{m}~\text{s}^{-1}]$ can be converted amongst any of the units below, \begin{equation} [\text{m}~\text{s}^{-1}] \equiv [\text{km}~\text{ks}^{-1}] \equiv [\text{hm}~\text{hs}^{-1}] \equiv [\text{dam}~\text{das}^{-1}] \equiv [\text{dm}~\text{ds}^{-1}] \equiv [\text{cm}~\text{cs}^{-1}] \equiv [\text{nm}~\text{ns}^{-1}], \end{equation} without modifying the numerical value of the quantity.

The function `PSUnitAreEquivalentUnits` can be used to test whether two units are equivalent, and can be substituted for each other without modifying the numerical value of the quantity. In the example code below, the function

`PSUnitRef unit1 = PSUnitForSymbol(CFSTR("m/s"),NULL));`

PSUnitRef unit2 = PSUnitForSymbol(CFSTR("km/ks"),NULL));
bool result = PSUnitAreEquivalentUnits(unit2, unit2);
would return `result = true`.

Conversely, while the function `PSUnitForSymbol` is capable of parsing the input string for any valid SI unit, it is possible that the unit returned is not equivalent to the unit in the parsed string. For example, consider the code below

```
double unit_multiplier = 1;
PSUnitRef forceUnit = PSUnitForSymbol(CFSTR("dm*m"),&unit_multiplier);
```

Generally, PhySyUnits always returns a unit using one symbol for each of the seven base dimensions. In this case, returning a unit of either `dm^2` or `m^2` would not be equivalent to the `dm*m`. Thus, any number associated with `dm*m` would need to be modified if it is to be associated with either `dm^2` or `m^2`. Thus, an additional variable `unit_multiplier` is passed to the function and returned multiplied by the necessary conversion.

In the SI system there is a set of 22 coherent derived units contained within the set of coherent derived SI units that, for convenience, have their own special names and symbols. The 22 special names and symbols and their corresponding coherent derived units are given below.

Derived Quantity | Name | Plural Name | Symbol | Coherent Derived SI Symbol |
---|---|---|---|---|

plane angle | radian | radians | rad | (m/m) |

solid angle | steradian | steradians | sr | (m$^2$/m$^2$) |

frequency | hertz | hertz | Hz | s$^{-1}$ |

force | newton | newtons | N | m kg s$^{-2}$ |

pressure, stress | pascal | pascals | Pa | m$^{-1}$ kg s$^{-2}$ |

energy, work, heat | joule | joules | J | m$^{2}$ kg s$^{-2}$ |

power, radiant flux | watt | watts | W | m$^{2}$ kg s$^{-1}$ |

electric charge | coulomb | coulombs | C | s A |

electric potential difference | volt | volts | V | m$^{2}$ kg s$^{-3}$ A$^{-1}$ |

capacitance | farad | farads | F | m$^{-2}$ kg$^{-1}$ s$^{4}$ A$^{2}$ |

resistance | ohm | ohms | $\Omega$ | m$^{2}$ kg s$^{-3}$ A$^{-2}$ |

electric conductance | siemens | siemens | S | m$^{-2}$ kg$^{-1}$ s$^{3}$ A$^{2}$ |

magnetic flux | weber | webers | Wb | m$^{2}$ kg s$^{-2}$ A$^{-1}$ |

magnetic flux density | tesla | tesla | T | kg s$^{-2}$ A$^{-1}$ |

inductance | henry | henry | H | m$^{2}$ kg s$^{-2}$ A$^{-2}$ |

Celsius Temperature | degree Celsius | degrees Celsius | $^\circ$C | K |

luminous flux | lumen | lumens | lm | (m$^2$/m$^2$) cd |

illuminance | lux | lux | lx | m$^{-2}$ cd |

radionuclide activity | becquerel | becquerel | Bq | s$^{-1}$ |

absorbed dose | gray | grays | Gy | m$^{2}$ s$^{-2}$ |

dose equivalent | sievert | sieverts | Sv | m$^{2}$ s$^{-2}$ |

catalytic activity | katal | katal | kat | s$^{-1}$ mol |

For example, the coherent derived SI unit: `m•kg/s^2`, used for the derived quantity of force, is given the special name `newton` and replaced with the symbol `N`. Therefore, to include the ability to substitute a special SI unit name and symbol for one of these 22 coherent derived units, PhySyUnits includes three additional attributes of name, plural name, and symbol for derived units that are a special SI unit.

`PSUnitRef forceUnit = PSUnitForSymbol(CFSTR("kN"),NULL);`

With the introduction of special SI symbols there is the additional possibility of derived quantities with derived units employing a special SI unit. Generally, however, no more than one special SI symbol appears in such a derived unit symbol and the special SI symbol often appears as a linear term in the numerator. For example, the derived quantity dynamic viscosity can use the derived unit `Pa•s` as well as `kg/(m•s)`. The derived quantity of surface tension can use the derived unit `N/m` as well as `kg/s^2`.

There are a number of units outside the International System of Units that continue to be used in different science and engineering communities. As mentioned earlier, the physical laws relating physical quantities are independent of any reference unit, and it is only the ratio of measured physical quantities that is physically significant. To handle such Non-SI Units in our data model, the four attributes added for Special SI Units of name, plural name, symbol, and symbol prefix can be employed in the same manner for Non-SI Units. Moreover, a boolean attribute is added to the unit data model to distinguish between Special SI Units and Non-SI units. While the 22 units in the set $[Q]_\text{SU}$ are equivalent to 22 coherent derived units contained within $[Q]_\text{DU}$, this will not be the case with Non-SI units. Thus, the final attribute in our unit data model will be a scaling between the Non-SI root unit and the coherent SI base unit or coherent derived SI unit with the same dimensionality. While derived unit using a non-SI unit will be allowed as input, the quantity (numerical value and unit) will immediate be converted to SI. For example, a quantity created by parsing ``1.0 in/s'' would be stored as 2.54 cm/s.

While it is straightforward to include non-SI unit symbols in the same manner as special SI unit symbols, one has to be careful to avoid symbol and name collisions, particularly as some non-SI unit symbols employ SI prefixes. Derived units employing non-SI symbols would be a more significant challenge. A more versatile approach might be to allow multiple systems of measurement, each with its own set of seven base reference quantities.

```
double unit_multiplier = 1;
PSUnitRef pressureUnit = PSUnitForSymbol(CFSTR("lb/in^2"),&unit_multiplier);
```

As with PSDimensionality, PhySy uses a Flyweight design pattern for PSUnit. As such, there is no need for memory management of PSUnit instances. Notice that there is no create nor copy functions. PhySy maintains an internal library of PSUnit instances and, for a given unit, PhySy will always return the same pointer reference. When a unit is requested that doesn't exist in the library, PhySy will create and add that instance to the library. Therefore, there is no need to send a CFRetain or CFRelease to any PSUnit.

See the full API of PSUnit here.

In the SI System seven reference quantities are used to define seven dimensions whose symbols are given below.

Reference Quantity | Dimension Symbol |
---|---|

length | L |

mass | M |

time | T |

electric current | I |

thermodynamic temperature | ${\Theta}$ |

amount of substance | N |

luminous intensity | J |

The dimensionality of any physical quantity, $q$, can then be expressed in terms of the seven reference dimensions in the form of a dimensional product \begin{equation} \mbox{dim} \, q = \text{L}^\alpha \text{M}^\beta \text{T}^\gamma \text{I}^\delta{\Theta}^\epsilon \text{N}^\zeta \text{J}^\eta, \end{equation} where the lower case greek symbols represent integers called the dimensional exponents. Dimensionality can also be represented as a point in the space of dimensional exponents $(\alpha, \beta, \gamma, \delta, \epsilon, \zeta, \eta)$. Physical quantities with different meanings can have the same dimensionality. For example, the thermodynamic quantities entropy and heat capacity are different physical quantities having the same physical dimensions. Only physical quantities with the same dimensionality can be added. With the operation of multiplication the physical dimensions form a group.

There also exists dimensionless quantities, such as the angle which has dimensionality of $\text{L}/\text{L}$, or the solid angle with a dimensionality of $\text{L}^2/\text{L}^2$. Representing such dimensionalities requires us to split each dimension exponent into numerator and denominator exponents. Thus, we keep track of these possibilities in PhySy by defining \begin{equation} \mbox{dim} \, q = \left[\frac{\text{L}^{\alpha_+}}{\text{L}^{\alpha_-}} \right] \cdot \left[\frac{\text{M}^{\beta_+}}{\text{M}^{\beta_-}} \right] \cdot \left[\frac{\text{T}^{\gamma_+}}{\text{T}^{\gamma_-}} \right] \cdot \left[\frac{\text{I}^{\delta_+}}{\text{I}^{\delta_-}} \right] \cdot \left[\frac{{\Theta}^{\epsilon_+}}{{\Theta}^{\epsilon_-}} \right] \cdot \left[\frac{\text{N}^{\zeta_+}}{\text{N}^{\zeta_-}} \right] \cdot \left[\frac{\text{J}^{\eta_+}}{\text{J}^{\eta_-}} \right]. \end{equation}

Dimensionalities in PhySy can be obtained simply with the identifier of the physical quantity. For example,

`PSDimensionalityRef force = PSDimensionalityForQuantity(kPSQuantityForce); `

A full list of identifiers can be found here
A dimensionality is displayed in the terminal using

`PSDimensionalityShow(force);`

which would display

`L•M/T^2`

Another way to obtain a dimensionality is using any combination of the symbols for the seven base dimensions, length, mass, time, current, temperature, amount, and luminous intensity, which are L, M, T, I, ϴ, N, and J, respectively. For example,

`PSDimensionalityRef acceleration = PSDimensionalityForSymbol(CFSTR("L/T^2")); `

Additionally, one can create a new dimensionality through the mathematical operations of multiplication, division, and exponentiation. For example,

```
PSDimensionalityRef mass = PSDimensionalityByDividing(force,acceleration);
PSDimensionalityShow(mass);
```

would display
`M`

As an example of multiplication,

```
PSDimensionalityRef distance = PSDimensionalityForQuantity(kPSQuantityDistance);
PSDimensionalityRef work = PSDimensionalityByMultiplying(force, distance);
PSDimensionalityShow(work);
```

would display
and raising to a power,`L^2•M/T^2`

```
PSDimensionalityRef area = PSDimensionalityByRaisingToAPower(distance, 2);
PSDimensionalityShow(area);
```

would display
`L^2`

In the three functions, `PSDimensionalityByMultiplying`, `PSDimensionalityByDividing`, and `PSDimensionalityByRaisingToAPower`, the numerator and denominator exponents of the returned dimensionality are always reduced to their lowest possible integer values consistent with the dimensionality of the result. If desired, this reduction of numerator and denominator exponents can be avoided with the otherwise identical functions, `PSDimensionalityByMultiplyingWithoutReducing`, `PSDimensionalityByDividingWithoutReducing`, and `PSDimensionalityByRaisingToAPowerWithoutReducing`.

This ability is can be quite useful when dealing with dimensionless quantities. For example, the function call

`PSDimensionalityRef angle = PSDimensionalityByDividing(distance,distance);`

would result in
`PSDimensionalityShow(angle);`

displaying
`1`

Likewise, the function call

`PSDimensionalityRef solidAngle = PSDimensionalityByDividing(area,area);`

would result in
`PSDimensionalityShow(solidAngle);`

also displaying
`1`

Both of these operations returned the same dimensionless dimensionality, i.e., ** 1**. If we instead call

```
PSDimensionalityRef angleDerived = PSDimensionalityByDividingWithoutReducing(distance,distance);
PSDimensionalityRef solidAngleDerived = PSDimensionalityByDividingWithoutReducing(area,area);
```

then, calling
`PSDimensionalityShow(angleDerived);`

would return
`L/L`

`PSDimensionalityShow(solidAngleDerived);`

would return
`L^2/L^2`

Thus, while the result of

`PSDimensionalityEqual(angle,solidAngle);`

is `PSDimensionalityEqual(angleDerived,solidAngleDerived);`

is On the other hand, the results of both

`PSDimensionalityHasSameReducedDimensionality(angle,solidAngle);`

and
`PSDimensionalityHasSameReducedDimensionality(angleDerived,solidAngleDerived);`

are Testing if a dimensionality is dimensionless is accomplished with the function:

`PSDimensionalityIsDimensionless(angleDerived);`

which, in this context, would return PhySy uses a Flyweight design pattern for PSDimensionality. As such, there is no need for memory management of PSDimensionality instances. Notice that there is no create nor copy functions. PhySy maintains an internal library of PSDimensionality instances and, for a given dimensionality, PhySy will always return the same pointer reference. When a dimensionality is requested that doesn't exist in the library, PhySy will create and add that instance to the library. Therefore, there is no need to send a CFRetain or CFRelease to any PSDimensionality.

See the full API of PSDimensionality here.

PSBlock represents a block of physical quantities. It is a concrete subtype of PSQuantity. It has three essential attributes: a unit, an elementType, and a block of numerical values.

See the full API of PSBlock here.PSDataset represents signal responses in a multi-dimensional coordinate system. A PSDataset has two essential attributes, an array of PSSignals, each with identical number and type of response values, and an array of PSDimensions, which define each of the dimensions along which the PSSignals are sampled.

See the (poorly documented) API of PSDataset here.PSSignal represents a block of physical responses. It is a subtype of PSBlock. Like PSBlock, it has three essential attributes: a unit, an elementType, and a block of numerical values. Additionally, a PSSignal can have three optional attributes: an array of coordinates, a response uncertainty, and a name.

A number of PSSignal's advanced methods require on an ordered array of PSDimension types.

See the full API of PSSignal here.PSDimension describes a uniformly sampled coordinate.

See the full API of PSDimension here.PSDatum represents a physical response in a coordinate space. It is a subtype of PSScalar. Like PSScalar, it has three essential attributes: a unit, an elementType, and a numerical value. Additionally, a PSDatum, like PSSignal, can have two optional attributes: an array of coordinates, and a response uncertainty.

Two optional transient attributes are memOffset and signalIndex, to indicate the origin for datum derived from a PSDataset

See the full API of PSDatum here.PSIndexArray represents an immutable collection of unique signed integers, known as indexes because of the way they are used. This collection is referred to as an index array.

See the full API of PSIndexArray here.PSIndexPairSet represents an immutable collection of unique integer pairs.

The PSIndexPair type is a structure containing two integers: an index and a value; The index can only appear once in the index pair set. A value has no such limitation. The mutable type of PSIndexPairSet is PSMutableIndexSet.

See the full API of PSIndexPairSet here.