CONTAINERS AND METHODS
In
X++, container is one of the primitive types, or
value types. container is not a class. A container contains an ordered sequence of
primitive values or other containers.
A container can be stored in the database. container is one of the column types that you
can select when you use the Application Object Tree (AOT) to add a column to a
table.
A container slightly resembles an array, or
collections such as the List or Stack classes.
However, you can never change the size or content of a container after the container is created. X++ statements that appear
to modify a container are internally building a new container and copying values as necessary. Even
an assignment of a container to
another container variable creates a new copy of the container.
All of this has performance implications.
In the
X++ functions that provide access to a container (such
as conPeek), the container is
1 based not 0 based. Indexing is 1 based for arrays, and for everything else in
X++.
Syntax
This
section describes the X++ syntax you must use to handle a container.
Operators
The
following table shows the X++ operators that can be applied to the container type.
|
Operator
|
Example
|
Description
|
|
=
|
myContainer2 =
[2, "apple"];
myContainer33 =
[33, "grape"];
myContainer2 =
myContainer33;
|
The example initializes myContainer2 and myContainer33.
Next, it makes a copy of myContainer33, and assigns the copy to myContainer2.
The container that myContainer2 had been holding is no longer available (and cannot be
recovered).
|
|
+=
|
myContainer33
+= [34, "banana"];
|
Builds a new container and
assigns it to myContainer33. The new container is
populated by appending the assigned elements to those in the original myContainer33.
The original myContainer33 is no longer available.
|
Statements
The
following table displays the syntax of statements that handle a container.
|
Action
|
Example
|
|
Declare a container
|
container cr3;
|
|
Assign a literal container to a container variable
|
cr3 = [22,
"blue"];
|
|
Declare and assign a container
|
container cr2 =
[1, "blue", true];
|
|
Mimic container modification
(implicitly creates a copy)
|
cr3 += [16,
strMyColorString];
cr3 =
conIns(cr3, 1, 3.14);
cr3 =
conPoke(cr3, 2, "violet");
|
|
Assignment of a container (implicitly
creates a copy)
|
cr2 = cr3;
|
|
Read a value from the container
|
myStr =
conPeek(cr2, 1);
|
|
One statement that does multiple assignments from a container
|
str myStr;
int myInt;
container cr4 =
["Hello", 22, 20\07\1988];
;
[myStr, myInt]
= cr4; // "Hello", 22
|
Functions
There
are several intrinsic X++ functions for handling a container,
such as conIns and conPeek. For more information about the intrinsic
X++ functions for handling a container, see Functions
for Manipulating Container Content.
The Global Class has static methods for handling
containers. Among those methods are the following:
·
con2ArraySource
·
con2Buf
·
con2List
·
con2Str
·
containerFromXmlNode
·
conView
·
str2Con
Container is a Value Type, not a
Reference Type
Any
class is a reference type. But container is
a value type. Variables declared as value types are never null. Even the X++
function conNull returns
a container.
A variable declared as a container is
automatically initialized to an empty container (a container that contains no values).
There
are two code samples in the following table. In only the List class
sample do variable2 and variable33 refer to the same thing (the same List object).
In the container sample, the two variables hold
different containers.
|
container
|
List class
|
|
X++
static void JobC(Args _args)
{
container variable2
,variable33;
;
variable2 += [98];
variable33 = variable2;
variable2 += [97];
}
|
X++
static void JobL(Args _args)
{
List variable2
,variable33;
;
variable2 = new List
(Type::Integer);
variable2.addEnd(98);
variable33 = variable2;
variable2.addEnd(97);
}
|
Containers are Immutable
Some
X++ statements with containers might appear like they modify a container,
but inside the system this never occurs. Instead, the data from the original container is combined with data from the command
to build a new container.
You
create a new container every time that you call any of the
following functions:
·
conDel
·
conIns
·
conPoke
The
following statements all create a new container:
·
myContainer =
[1];
·
myContainer +=
[2];
·
myContainer4 =
myContainer5;
Automatic Type Conversions by
Anytype
The
X++ function conPeek returns an anytype type. The flexibility of anytype makes container a good way to store values of
different types together. This makes it easier to read the values from a container when you do not know what type each
value is. An anytype can be assigned to any X++ value type,
as long as the value can be converted.
The
automatic conversion by anytype also
applies to the special syntax for making multiple assignments from a container in one statement. This is shown in the
following code example, which assigns a str to
an int,
and an int to a str.
X++
static void JobContainerMultiAssignmentUsesAnytype(Args _args)
{
container con2;
int int4;
str str7;
con2 = ["11", 222];
[int4, str7] = con2;
info(strfmt("int4==11==(%1), str7==222==(%2)"
, int4, str7));
}
/*** Pasted from output:
Message (10:36:22 am)
int4==11==(11), str7==222==(222)
***/
Your
code is easier to read when it avoids implicit data type conversions. Assign
values from a container to the same data type that was used to
put the value into the container.
You
must not assign a container to
an anytype,
because the system is unable to determine the correct conversions in some
cases. In these cases, unexpected behavior or errors might occur.
Performance of Containers
A container is best suited for processes that do
not involve excessive modification to the size or contents of the container.
When a container undergoes excessive additions of data,
overall system performance can be decreased by the need to repeatedly copy container data and allocate new space.
+= is Faster Than conIns
When
you want to build a new container by
appending new data, you can use either the += operator
or the conIns function.
The += operator is the faster alternative.
Use the conIns function
only when you want to add new data before the last index of the original data.
Comparing container to other
Options
The container type slightly resembles other
constructs, such as arrays and collection classes like List and Stack. The next sections compare and contrast container with these other options.
Differences Between container and
List
An
instance of the List class
is mutable. A List object
first allocates more space than its data consumes. As data is added the space
is filled. This is more efficient than allocating more space every time that an
element is added. Updating a List performs
faster than similar operations on a container.
When
you construct a List object,
you determine the one type of data that the List object
can store. This restriction is less flexible than for a container.
However, you can choose to store objects in a List, whereas a container can only store value types.
|
Note
|
|
For more information about X++ data types, see Data Types in X++.
|
Differences Between container and
an Array
An
array can hold only items of its declared type.
You
can allocate memory space for an array and fill that space with values later,
such as in a loop. This is efficient and performs well.
conDel Function
Removes
the specified number of elements from a container.
container conDel(container container, int start, int number)
Parameters
|
Parameter
|
Description
|
|
container
|
The container from which to remove elements.
|
|
start
|
The one-based position at which to start removing
elements.
|
|
number
|
The number of elements to delete.
|
Return Value
A new
container without the removed elements.
Example
X++
static void conDelExample(Args _args)
{
container c = ["Hello world", 1, 3.14];
;
// Deletes the first two items from the container.
c = conDel(c, 1, 2);
}
conFind Function
Locates
the first occurrence of an element or a sequence of elements in a container.
int conFind (container container, anytype element,... )
Parameters
|
Parameter
|
Description
|
|
container
|
The container to search.
|
|
element
|
One or more elements to search for, separated by
commas.
|
Remarks
If
several elements are specified in the sequence, they must be separated by
commas and specified in the correct sequence. The elements can be of any data
type.
Return Value
Returns
0 if the item was not found; otherwise, the sequence number of the item.
Example
X++
static void conFindExample(Args _args)
{
container c = ["item1", "item2", "item3"];
int i;
int j;
;
i = conFind(c, "item2");
j = conFind(c, "item4");
print "Position of 'item2' in container is " + int2Str(i);
print "Position of 'item4' in container is " + int2Str(j);
pause;
}
conIns Function
Inserts
one or more elements into a container.
container conIns (
container container,
int start,
anytype element,
... )
Parameters
|
Parameter
|
Description
|
|
container
|
The container into which to insert elements.
|
|
start
|
The position at which to insert elements.
|
|
element
|
One or more elements to insert, separated by commas.
|
Return Value
The
new container with the inserted elements.
Remarks
The
first element of the container is specified by the number 1. To insert after
the n element, the start parameter should be n+1.
You
can also use the += operator
to add values of any type into a container. For example, to create a container
that contains the squared values of the first 10 loop iterations:
X++
int i;
container c;
;
for (i = 1; i < = 10; i++)
{
c += i*i;
}
Example
X++
static void conInsExample(Args _arg)
{
container c;
int i;
;
c = conIns(c,1,"item1");
c = conIns(c,2,"item2");
for (i = 1 ; i <= conLen(c) ; i++)
{
// Prints the content of a container.
print conPeek(c, i);
}
pause;
}
conLen Function
Retrieves
the number of elements in a container.
int conLen(container container)
Parameters
|
Parameter
|
Description
|
|
container
|
The container in which to count the number of elements.
|
Return Value
The
number of elements in the container.
Example
X++
static void conLenExample(Args _arg)
{
container c;
int i;
;
c = conins(["item1", "item2"], 1);
for (i = 1 ; i <= conLen(c) ; i++)
{
print conPeek(c, i);
}
pause;
}
conPoke Function
Modifies
a container by replacing one or more of the existing elements.
container conPoke(
container container,
int start,
anytype element,
...)
Parameters
|
Parameter
|
Description
|
|
container
|
The container to modify.
|
|
start
|
The position of the first element to replace.
|
|
element
|
One or more elements to replace, separated by commas.
|
Return Value
The
new container with the new elements.
Remarks
The
first element of the container is specified by the number 1.
Example
X++
static void conPokeExample(Args _arg)
{
container c1 = ["item1", "item2", "item3"];
container c2;
int i;
void conPrint(container c)
{
for (i = 1 ; i <= conLen(c) ; i++)
{
print conPeek(c, i);
}
}
;
conPrint(c1);
c2 = conPoke(c1, 2, "PokedItem");
print "";
conPrint(c2);
pause;
}