Type
Used at the module level to define a user-defined data type containing one or more elements.
Syntax:
[ attributes ]
[ Private | Public ] Type varname [ ( Of typevars ) ]
elementname [ ( [ subscripts ] ) ] As type
[ elementname [ ( [ subscripts ] ) ] As type ]
. . .
[ member-procedure ]
. . .
End Type
- attributes
- optional (twinBASIC) Type-level attributes. Most notably PackingAlignment, which sets the field-alignment value used when laying out the UDT in memory — useful for interop with C structs declared under
#pragma packor#include <pshpack1.h>. - Public
- optional Used to declare user-defined types that are available to all procedures in all modules in all projects.
- Private
- optional Used to declare user-defined types that are available only within the module where the declaration is made.
- varname
- Name of the user-defined type; follows standard variable naming conventions.
- elementname
- Name of an element of the user-defined type. Element names also follow standard variable naming conventions, except that keywords can be used.
- subscripts
- optional Dimensions of an array element. When not explicitly stated in lower, the lower bound of an array is controlled by the Option Base statement. The lower bound is zero if no Option Base statement is present.
- type
- Data type of the element; may be Byte, Boolean, Integer, Long, LongLong, LongPtr, Currency, Single, Double, Decimal, Date, String (for variable-length strings), String length (for fixed-length strings), Object, Variant, another user-defined type, or an object type. In a generic Type (see below), type may also be one of the typevars introduced in the Of clause.
- Of typevars
- optional (twinBASIC) One or more type variable names, separated by commas, that make the Type a generic UDT. Each type variable can be referenced as the type of an element. See Generics. Generic UDTs do not yet support member procedures.
- member-procedure
- optional (twinBASIC) A Sub, Function, or Property procedure, or a Declare external procedure, written inside the Type body and callable through any variable of that type. See twinBASIC enhancements below.
The Type statement can be used only at the module level. After a user-defined type has been declared by using the Type statement, a variable of that type can be declared anywhere within the scope of the declaration. Use Dim, Private, Public, ReDim, or Static to declare a variable of a user-defined type.
In standard modules and class modules, user-defined types are public by default. This visibility can be changed by using the Private keyword.
Line numbers and line labels aren’t allowed in Type…End Type blocks.
User-defined types are often used with data records, which frequently consist of a number of related elements of different data types.
The following example shows the use of fixed-size arrays in a user-defined type:
Type StateData
CityCode (1 To 100) As Integer ' Declare a static array.
County As String * 30
End Type
Dim Washington(1 To 100) As StateData
In the preceding example, StateData includes the CityCode static array, and the record Washington has the same structure as StateData.
When a fixed-size array is declared within a user-defined type, its dimensions must be declared with numeric literals or constants rather than variables.
Example
This example uses the Type statement to define a user-defined data type. The Type statement is used at the module level only. If it appears in a class module, a Type statement must be preceded by the keyword Private.
Type EmployeeRecord ' Create user-defined type.
ID As Integer ' Define elements of data type.
Name As String * 20
Address As String * 30
Phone As Long
HireDate As Date
End Type
Sub CreateRecord()
Dim MyRecord As EmployeeRecord ' Declare variable.
' Assignment to EmployeeRecord variable must occur in a procedure.
MyRecord.ID = 12003 ' Assign a value to an element.
End Sub
twinBASIC enhancements
twinBASIC extends classic VBA’s Type in several ways. UDTs remain stack-allocated structs that can be passed to Win32 APIs, but they can also have behaviour like a lightweight class.
Member procedures. Sub, Function, and Property procedures may appear inside Type ... End Type, and are called through any variable of the type. Inside a member procedure, other members of the same UDT must be accessed with the explicit Me. prefix.
Lifecycle and operator hooks. Well-known member names are connected by the compiler:
| Member | Purpose |
|---|---|
Type_Initialize | Constructor — runs when a variable of the type is created. |
Type_Terminate | Destructor — runs when the variable goes out of scope. |
Type_Assignment | Assignment operator — = assigns RHS to a variable of the type. The signature is Sub Type_Assignment(ByVal RHS As ...), and several overloads with different RHS types may coexist. |
Type_Conversion | Conversion operator — produces a value of another type from the UDT. The signature is Function Type_Conversion() As ..., and several overloads with different return types may coexist. |
Type_DebugView | Debugger display — returns a String shown in the IDE’s variable inspector. |
API declarations inside a UDT. A Declare statement inside a Type body works as a regular module-level declaration, except that when its first parameter is named Me and is the same type as the UDT, calls on a variable of that type pass the variable as the first argument implicitly:
Type HWND
Value As LongPtr
Public Declare PtrSafe Function BringWindowToTop Lib "user32" (ByVal Me As HWND) As Long
End Type
Dim h As HWND
h.BringWindowToTop() ' Passes h as the first argument to the API.
Custom packing. The PackingAlignment type-level attribute controls alignment of the UDT’s fields. The default packing places each field at a multiple of its own size (with trailing padding so the total size is a multiple of the largest field). Setting [PackingAlignment(1)] packs fields with no padding — matching #pragma pack(push, 1) in C.
[PackingAlignment(2)]
Private Type MyUDT
x As Integer
y As Long
z As Integer
End Type
Generic types. A type variable list (Of T) after the varname makes the Type generic. Element types may then reference the type variables. Member procedures are not yet supported on generic UDTs.
Type ListU(Of T)
value() As T
End Type