Type
Declares a user-defined type.
Syntax
`
Type typename
fieldname1 As DataType
fieldname2 As DataType
As DataType fieldname3, fieldname4
...
End Type
Type typename [Extends base_typename] [Field = alignment]
[Private:|Public:|Protected:]
Declare Sub|Function|Constructor|Destructor|Property|Operator ...
Static variablename As DataType
fieldname As DataType [= initializer]
fieldname(array dimensions) As DataType [= initializer]
fieldname : bits As DataType [= initializer]
As DataType fieldname [= initializer], ...
As DataType fieldname(array dimensions) [= initializer], ...
As DataType fieldname : bits [= initializer], ...
Union
fieldname As DataType
Type
fieldname As DataType
...
End Type
...
End Union
...
End Type
`
Description
`Type` is used to declare custom data types containing one or more data fields, including integer types, floating point types, fixed-size arrays, strings, bitfields, and other unnamed user-defined types or unions.
Types support various functionality related to object-oriented programming:

- Inheritance through the use of the Extends keyword
- Member procedures such as Subs or Functions
- Member procedures with special semantic meaning such as Constructors or a Destructor
- Member visibility specifiers: `Public:`, `Private:`, `Protected:`

Memory layout
Types lay out their fields consecutively in memory, following the native alignment and padding rules (described on the `Field` page). Special care must be taken when using Types for file I/O or interacting with other programs or programming languages, in case the alignment and padding rules are different. The optional `Field = number` specifier can be used to change the behavior on the FreeBASIC side.
Dynamic data
Types can contain dynamic strings, but note that the Type will contain the `String` descriptor structure, not the string data itself, which afterall is dynamically allocated and can be of variable length, and thus can not be inserted into the Type. Because of that, saving such a Type into a file will write out the string descriptor, not the actual string data. In order to embed strings into Types directly, fixed-length strings must be used. Similarly, when maintaining dynamic data manually through the use of pointers within a Type, it does usually not make sense to save the Type to a file, because the address stored in the pointer field will be written to file, not the actual memory it points to. Addresses are meaningful to a specific process only though, and cannot be shared that way.
Special note on fixed length strings
Currently, fixed-length string fields of `String * N` type have an extra null terminator at their end, for compatibility with C strings, making them incompatible with QB strings inside Types, because they actually use up `N+1` bytes, instead of just `N` bytes. A possible work-around is to declare the field `As String * (N-1)`, though this will not work in future releases if the null terminator is removed. Another alternative is to use a `Byte` or `UByte` array with the proper size.
Remark
Nested unnamed type or union cannot have function members.
Example
This is an example of a QB-style type, not including procedure definitions
`
Type clr
red As UByte
green As UByte
blue As UByte
End Type
Dim c As clr
c.red = 255
c.green = 128
c.blue = 64
`
And this is an example of a type working as an object:
`
'' Example showing the problems with fixed length string fields in UDTs
'' Suppose we have read a GIF header from a file
'' signature width height
Dim As ZString*(10+1) z => "GIF89a" + MKShort(10) + MKShort(11)
Print "Using fixed-length string"
Type hdr1 Field = 1
As String*(6-1) sig /' We have to dimension the string with 1 char
' less to avoid misalignments '/
As UShort wid, hei
End Type
Dim As hdr1 Ptr h1 = CPtr(hdr1 Ptr, @z)
Print h1->sig, h1->wid, h1->hei '' Prints GIF89 (misses a char!) 10 11
'' We can do comparisons only with the 5 visible chars and creating a temporary string with LEFT
If Left(h1->sig, 5) = "GIF89" Then Print "ok" Else Print "error"
'' Using a ubyte array, we need an auxiliary function to convert it to a string
Function ub2str( ub() As UByte ) As String
Dim As String res = Space(UBound(ub) - LBound(ub) + 1)
For i As Integer = LBound(ub) To UBound(ub)
res[i - LBound(ub)] = ub(i)
Next
Function = res
End Function
Print
Print "Using an array of ubytes"
Type hdr2 Field = 1
sig(0 To 6-1) As UByte '' Dimension 6
As UShort wid, hei
End Type
Dim As hdr2 Ptr h2 = CPtr(hdr2 Ptr, @z)
'' Viewing and comparing is correct but a conversion to string is required
Print ub2str(h2->sig()), h2->wid, h2->hei '' Prints GIF89a 10 11 (ok)
If ub2str(h2->sig()) = "GIF89a" Then Print "ok" Else Print "error" '' Prints ok
`
Platform Differences

- The default `Field` alignment parameter is 4 bytes for DOS and Linux targets.
- The default `Field` alignment parameter is 8 bytes for Windows targets (this difference with regard to 4 bytes applies only to Longint and Double members).

Dialect Differences

- Object-related features such as functions declared inside `Type` blocks are supported only with the -lang fb dialect since version 0.17b
- In the -lang fb and -lang fblite dialects, the default `Field` alignment parameter depends on the target platform.
- With the -lang qb dialect the fields are aligned to byte boundaries by default, unless otherwise specified.
- To force byte alignment use `FIELD=1`.

Differences from QB

- At present, fixed-length strings have an extra, redundant character on the end, which means they take up one more byte than they do in QB. For this reason, UDTs that use them are not compatible with QB when used for file I/O.

See also

- `Type (Alias)`
- `Type (Temporary)`
- `Union`
- `Enum`
- `TypeOf`
- `OffsetOf`
- `Field`
- `Extends`
- `With`