# Polymorphic Type¶

A new data type is a polymorphic data type. The type can really be used to store anything, but also has simple conversion methods for common data types such as bool, long, or a vector.

The polymorphic type simplifies message passing between blocks, as all of the data is of the same type, including the message. Tags also use PMTs as data type, so a stream tag can be of any logical data type. In a sense, PMTs are a way to extend C++' strict typing with something more flexible.

## PMT Types¶

The PMT library supports the following major types. Some of the more complex types have their own wiki page for assistance.*bool*- just like a C++ boolean, true or false*symbol*- easiest to think of it as a std::string*integer*- int, long, unsigned*real*- double, float*complex*- gr_complex, std::complex*null*- NULL*pair*- a 2-tuple data type*list*- a list*vector*- a vector of PMT objects*dict*- a dictionary (hash) like structure*uniform_vector*- a vector of typed objects (uint8_t, float, etc...)*any*- boost:any cast

## Making a PMT instance¶

To make PMT, the data type *pmt_t* is used just like any other data type.

The following is an example:

pmt_t p_instance;

## Constructing/Assigning a PMT¶

To construct or assign a value to a PMT, a method is available for each type of the following syntax: *pmt*<type>_.

*pmt_t*:

- pmt_bool()
- pmt_symbol(const std::string &)
- pmt_integer(long)
- pmt_real(double)
- pmt_complex(std::complex<double>)
- pmt_null()
- pmt_pair() or pmt_pair(pmt,pmt)
- pmt_vector(size_t,pmt)
- pmt_dict()
- pmt_make_*vector(size_t, *) -- see uniform vectors
- pmt_any(const boost::any &)

For example, pmt_integer(long) returns a pmt_t, constructed from a long:

pmt_t p_num = pmt_integer(3);

## Checking PMT Type¶

With a polymorphic type, it is useful to have methods to check what type it actually is if unknown.

The following methods are available for testing PMT types, all of which return*bool*:

- pmt_is_bool(pmt)
- pmt_is_symbol(pmt)
- pmt_is_number(pmt)
- pmt_is_integer(pmt)
- pmt_is_real(pmt)
- pmt_is_complex(pmt)
- pmt_is_null(pmt)
- pmt_is_pair(pmt)
- pmt_is_vector(pmt)
- pmt_is_uniform_vector(pmt)
- pmt_is_dict(pmt)
- pmt_is_any(pmt)

In this example, *test_pmt* will be assigned the value *true*:

```
pmt_t p_num = pmt_integer(3);
bool test_pmt = pmt_is_integer(p_num);
```

## PMT Constants¶

There are 3 main constant values in the PMT world which can be returned:*PMT_T*- PMT representation of true*PMT_F*- PMT representation of false*PMT_NIL*- PMT NIL/NULL representation

When a PMT is initialized with no value, such as *pmt_dict()* ... it is equivalent to PMT_NIL until it is assigned elements.

## Testing Equality¶

To test the equality of PMT types, the following methods are available.*pmt_eq(pmt_t, pmt_t)*- tests strict equality (the two parameters are the same)*pmt_eqv(pmt_t, pmt_t)*- tests for equivalence (the two parameters have the same value)*pmt_equal(pmt_t, pmt_t)*- tests for equivalence of multi-value types (pmt_pair, pmt_vector)

The following gives a good overview of equality testing:

```
pmt_t p1 = pmt_integer(5);
pmt_t p2 = pmt_integer(5);
pmt_t p3 = pmt_integer(1);
pmt_eq(p1, p1); // Returns true
pmt_eq(p1, p2); // Returns false
pmt_eqv(p1, p1); // Returns true
pmt_eqv(p1, p2); // Returns true
pmt_t p3 = pmt_pair(p1, p1);
pmt_t p4 = pmt_pair(p1, p2);
pmt_t p5 = pmt_pair(p1, p3);
pmt_equal(p3, p4); // Returns true, equivalence in values
pmt_equal(p3, p5); // Returns false, values are different
```

## PMT Conversion Methods¶

There are simple methods to store common C++ types as PMT for use in passing the data in m-block messages.

All of the conversion methods are of a similar syntax:*pmt_from*<type>_ - convert a C++ type to a PMT*pmt_to*<type>_ - convert a PMT to a C++ type

- bool, long, double, complex

For example:

```
pmt_t p_val = pmt_from_long(3);
long l_val = pmt_to_long(p_val);
```

In Python, you can use the pmt.to_python() and pmt.to_pmt() methods to convert, without having to know the type yourself (see below).

## Checking PMT Length¶

For variable length PMT types, such as list and vector, you can use the following method to check how many elements are in the PMT:- size_t pmt_length(pmt_t)

```
pmt_t p1 = pmt_integer(1);
pmt_t p2 = pmt_integer(2);
pmt_t p3 = pmt_integer(3);
pmt_t p_list = pmt_list3(p1, p2, p3);
pmt_length(p_list); // Returns 3
```

## Detailed Type Information¶

### Lists¶

PMT lists are as they sound, lists! Each list element is of type pmt_t, and the list can be of infinite length.

To create a base list, you can use the following methods:- pmt_list1(pmt_t)
- pmt_list2(pmt_t, pmt_t)
- pmt_list3(pmt_t, pmt_t, pmt_t)
- pmt_list4(pmt_t, pmt_t, pmt_t, ...)
- pmt_list5(pmt_t, pmt_t, pmt_t, ...)
- pmt_list6(pmt_t, pmt_t, pmt_t, ...)

- pmt_t pmt_list_add(pmt_t list, pmt_t object)

List items cannot be removed, as they are implemented as constants.

To access the nth element in a list, the following method is available which returns the nth element:- pmt_t pmt_nth(size_t n, pmt_t list)

The following exercises PMT lists:

```
pmt_t p_list1 = pmt_list1(PMT_T);
p_list1 = pmt_list_add(p_list1, PMT_F);
pmt_t p_list2 = pmt_list2(PMT_T, PMT_F);
pmt_equal(p_list1, p_list2); // Returns true
pmt_t p_element0 = pmt_nth(0, p_list2); // Access elements
pmt_t p_element1 = pmt_nth(1, p_list2);
pmt_eqv(p_element0, PMT_T); // Returns true
pmt_eqv(p_element1, PMT_F); // Returns true
```

### Uniform Vectors¶

Uniform PMT vectors are for storing vectors of common C++ types. The following types are supported:- uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t, float, double, std::complex<float>, std::complex<double>

*pmt_t*, where the first parameter is the number of elements to create and the second parameter is a fill parameter for initializing all of the elements to a specific value:

- pmt_make_u8vector(size_t, uint8_t)
- pmt_make_s8vector(size_t, int8_t)
- pmt_make_u16vector(size_t, uint16_t)
- pmt_make_s16vector(size_t, int16_t)
- pmt_make_u32vector(size_t, uint32_t)
- pmt_make_s32vector(size_t, int32_t)
- pmt_make_u64vector(size_t, uint64_t)
- pmt_make_s64vector(size_t, int64_t)
- pmt_make_f32vector(size_t, float);
- pmt_make_f64vector(size_t, double);
- pmt_make_c32vector(size_t, std::complex<float>)
- pmt_make_c64vector(size_t, std::complex<double>)

- pmt_<type>vector_ref(pmt_t, size_t)

The following is an example of uniform vectors:

```
static const int nelements = 64;
pmt_t s16vec = pmt_make_s16vector(nelements, 0); // Initializes all 64 elements to 0
size_t vec_size;
int16_t *elements = pmt_s16vector_writable_elements(s16vec, vec_size); // Returns pointer, vec_size is set to 64
// Now you can access the elements like a standard array
for(int i=0; i<vec_size; i++)
elements[i] = 1;
```

### Dictionaries¶

A dictionary behaves exactly like a hash. PMT objects are referenced with a pmt_symbol (string-like PMT type).

To create a dictionary, use:- pmt_t pmt_make_dict()

- dict = pmt_dict_add(pmt_t dict, pmt_t symbol, pmt_t value)

*error_val*if the symbol (hash key) did not exist:

- pmt_dict_ref(pmt_t dict, pmt_t symbol, pmt_t error_val)

- pmt_is_dict(pmt_t)

The following is an example of using dictionaries:

```
pmt_t p_dict = pmt_make_dict(); // Empty dictionary
p_dict = pmt_dict_add(p_dict, pmt_symbol("number of dogs"), pmt_integer(3));
p_dict = pmt_dict_add(p_dict, pmt_symbol("number of cats"), pmt_integer(5));
p_dict = pmt_dict_add(p_dict, pmt_symbol("has a dog"), PMT_T);
p_dict = pmt_dict_add(p_dict, pmt_symbol("has a turtle"), PMT_F);
if(pmt_is_dict(p_dict)) {
pmt_t p_ndogs = pmt_dict_ref(p_dict, pmt_symbol("number of dogs"), PMT_NIL);
pmt_t p_ncats = pmt_dict_ref(p_dict, pmt_symbol("number of cats"), PMT_NIL);
pmt_t p_dog = pmt_dict_ref(p_dict, pmt_symbol("has a dog"), PMT_NIL);
pmt_t p_turtle = pmt_dict_ref(p_dict, pmt_symbol("has a turtle"), PMT_NIL);
std::cout << "I have " << pmt_to_long(p_ndogs) << " dogs!\n";
std::cout << "I have " << pmt_to_long(p_ncats) << " cats!\n";
if(pmt_eqv(p_dog, PMT_T))
std::cout << "I have a dog\n"; // This will be outputted
else
std::cout << " I do not have a dog\n";
if(pmt_eqv(p_turtle, PMT_T))
std::cout << "I have a turtle\n";
else
std::cout << "I do not have a turtle\n"; // This will be outputted
}
```

### Any¶

When there is nothing to store your type, use a pmt_any. This allows you to cast anything into a pmt_t using boost::any cast.

Example:

```
typedef struct d_frame_hdr_t {
long src_addr;
long dst_addr;
} +attribute+((+packed+));
d_frame_hdr_t my_header;
my_header.src_addr = 3;
my_header.dst_addr = 4;
pmt_t p_any = pmt_make_any(my_header);
// After extracting using pmt_any_ref the following will be true:
// extract_header.src_addr == 3
// extract_header.dst_addr == 4
d_frame_hdr_t extract_header = boost::any_cast<d_frame_hdr_t> (pmt_any_ref(p_any));
```

## Conversion between Python Objects and PMTs¶

Although PMTs can be manipulating in python using the python versions of the C++ interfaces there are some additional goodies that make it easier to work with PMTs in python.

In particular there are functions to automate the conversion of python booleans, strings, integers, longs, floats, complex numbers, dictionaries, lists, tuples and combinations thereof into their equivalent PMTs.

Two functions capture most of this functionality.

- pmt.to_pmt - Converts a python object to a PMT.
- pmt.to_python - Converts a PMT into a python object.