Skip to content

Struct

See Also: - Declaring Variables: Array Declarations - Move - Struct Type - Struct Variables - Struct Declaration - Struct Variable Assignments - Struct Properties - SizeOfType

Purpose

Declares a new structured data type.

Syntax

Struct {type-name}
{data-type} {member-name}
[{data-type} {member-name}]
[]
End_Struct

or

Struct {type-name}
[ {Name={alternate-member-name} } ]
{data-type} {member-name}
[{data-type} {member-name}]
[]
End_Struct

Where:

  • {type-name} is the name of the new struct type. Struct type names must be unique symbols. DataFlex naming convention suggests prefixing struct type names with a lowercase 't'.

  • {data-type} is the data type of individual struct members. This can be any DataFlex simple type (Integer, Number, Real, Boolean, Date, String, Pointer, Handle), an array type, or another struct type.

  • {member-name} is the name assigned to each struct member. Struct member names must be unique within the declared struct. A struct cannot declare two members with the same name. Member names do not have to be unique outside the struct declaration. You may not use a DataFlex reserved word as a member name.

  • {alternate-member-name} is an optional Name meta-data tag that can be used to designate an alternate name to Struct members that is used when serializing and deserializing structs to and from JSON and XML. See Name meta-data tag for more information.

What It Does

A struct represents a set of elements where each element is called a member. A struct type declaration defines a particular set of elements and associates it with a new type identifier.

Once a struct type is declared, it can be used just like any other DataFlex data type. You may declare and use variables and properties, and you may declare procedure or function parameters and return types of a struct type. For example:

Struct tCreditCard    // declares a new struct type
    Integer iType
    String  sName
    Integer iNumber
    Date    dExpires
End_Struct

tCreditCard MyCreditCard  // declares a new variable of tCreditCard type

Members of a struct variable are accessed using the member access operator (the dot operator). For example:

Move 0                to MyCreditCard.iType
Move "Joe Bloggs"     to MyCreditCard.sName
Move 1234123412341234 to MyCreditCard.iNumber
Date dToday
Sysdate dToday
If (MyCreditCard.dExpires >= dToday) Showln "Expired!"

For each struct type defined, the compiler automatically defines the symbol _struct_{name} where {name} is replaced with the name of the struct type. This can be used at compile time to determine whether a particular struct type has been defined. For example:

#IFDEF _struct_tCreditCard
// Do something special if the tCreditCard struct type has been defined
...
#ENDIF

For more information, refer to struct types in the Language Guide.

Struct Alignment

Structure alignment (or structure padding) happens when structs are passed to other DLLs or Windows functions. This is because the compiler ensures that each struct instance will have the alignment of its widest scalar member (for performance reasons) and extra memory space may be inserted within the struct (unless structure alignment is explicitly switched off in the DLL).

DataFlex does not do structure alignment. This means that you might have to add extra padding items yourself to exposed Windows structs. This issue is especially relevant to the 64-bit platform. Take this example:

Struct tWinChooseFont
    DWord lStructSize
    Handle hwndOwner
End_Struct

In 32-bit, both DWord and Handle are 32-bit items (4 bytes), which does not lead to any padding. However, in 64-bit, Handle has become 64-bit (8 bytes) and that causes the struct to have 8-byte alignment, which means that in Windows compilers there will be 4 bytes of space inserted after lStructSize. If this doesn’t get corrected in 64-bit environments, there can be an unexpected runtime error or crash upon calling the external function. The solution in DataFlex code is:

Struct tWinChooseFont
    DWord lStructSize
    #IFDEF IS$WIN64
    Integer iStructAlignment
    #ENDIF
    Handle hwndOwner
End_Struct

Be aware that such changes might influence code where you do a SizeOfType() on that struct.

The structure alignment issue is not relevant to structs internal to your application (not passed to outside DLLs) or structs in COM class interfaces.

Examples

The following example demonstrates a nested struct declaration, i.e., a struct type with a member that is also a struct type.

Struct tAddress
    String Street
    String City
    String State
    Integer Zip
End_Struct

Struct tCompany
    String   Name
    tAddress PostalAddress
    tAddress Location
    Integer  Phone
End_Struct

The following example declares a struct variable named tStudent, then creates a dynamic array of type tStudent named myStudents. Next, a loop is created that finds Student records and fills the array with the information from the database.

// declare data type tStudent
Struct tStudent
    String FirstName
    String LastName
    String ClassName
    Integer LastTestScore
End_Struct

tStudent[] myStudents  // dynamic array of tStudent
open Student  // open Student table
integer i
for i from 0 to iNumberOfStudents
    clear Student
    move i to Student.Id
    find eq Student by 1  // Id
    if (Found) begin
        move Student.First     to myStudents[i].FirstName
        move Student.Last      to myStudents[i].LastName
        move Student.Class     to myStudents[i].ClassName
        move Student.TestScore to myStudents[i].LastTestScore
    end
loop

Example: Initializing Struct Variable Members

In the example below, move is used to initialize members of the myBillingAddress struct variable.

Struct tUSAddress
    String sFirstName
    String sLastName
    String sAddressLine1
    String sAddressLine2
    String sCity
    String sState
    Integer iZipCode
End_Struct

Procedure CreateBillingAddress
    tUSAddress myBillingAddress
    // initialize myBillingAddress
    move "John"                  to myBillingAddress.sFirstName
    move "Smith"                 to myBillingAddress.sLastName
    move "Data Access Worldwide" to myBillingAddress.sAddressLine1
    move "14000 SW 119 Ave"      to myBillingAddress.sAddressLine2
    move "Miami"                 to myBillingAddress.sCity
    move "FL"                    to myBillingAddress.sState
    move "33186"                 to myBillingAddress.iZipCode
End_Procedure

Example: Copying Struct Variable Members

Assume that the example below is a continuation of the sample above, using the same struct declaration for tUSAddress. Here, move is used to copy the value of myBillingAddress to myShippingAddress. Using move to copy struct variables uses a deep memberwise copy operation to copy each struct variable member value from the first struct variable to the second struct variable.

Procedure CreateShippingAddress tUSAddress myBillingAddress
    tUSAddress myShippingAddress
    move myBillingAddress to myShippingAddress
End_Procedure

Example: Re-initializing Struct Variable Members

There is a quick way to re-initialize array variables to their original (blank) values. Simply move an un-initialized array variable of the same type:

Struct tTest
    Integer iTest
    String sTest
End_Struct

Procedure Test
    tTest localTest blankTest
    // initialize localTest with values
    Move 104 to localTest.iTest
    Move "Fred" to localTest.sTest
    // re-initialize localTest elements to their original (blank) values
    Move blankTest to localTest
End_Procedure

The same can be done with struct properties:

Property tTest pMyTest

Procedure ReinitializepMyTest
    tTest blankTest
    Set pMyTest to blankTest
End_Procedure

Notes

  • You may not declare a member whose type is the same as the struct type being declared (i.e., recursive struct declarations are not allowed).

  • When declaring a static array struct member, the array dimension must be a constant value computed at compile time. For example, the declaration below is correct.

    Struct tContact
        String Company
        String[5] ContactNames
        Integer Fax
    End_Struct
    

    However, the following declaration will produce a compile-time error.

    Integer icNames
    Move 5 to icNames
    Struct tContact
        String Company
        String[icNames] ContactNames
        Integer Fax
    End_Struct
    

    This restriction does not apply to dynamic or jagged array struct members.

  • To see how to declare arrays of structs, see Declaring Variables: Array Declarations.