Generics Package

Author: mansellan.

The Generics contributed package provides seven tuple classes, TupleOf1 to TupleOf7. A tuple is a read-only object that holds one to seven values, called its items, each of a type given when the tuple is declared.

A tuple lets a function return several values at once, without a user-defined type declared for the purpose or ByRef parameters for the results. Each class is a generic class: TupleOf2(Of Long, String) holds a Long and a String, and its Item1 and Item2 properties return them with those types. The classes follow .NET’s System.Tuple classes, and their source comments are taken from .NET’s, under the MIT licence. This section documents version 1.0.0.0, published under the MIT licence.

Dim t As TupleOf3(Of String, Long, Date) = New TupleOf3(Of String, Long, Date)("Ada", 36, #12/10/1815#)
Debug.Print t.Item1        ' Ada
Debug.Print t.Item2        ' 36
Debug.Print Year(t.Item3)  ' 1815

Syntax

New TupleOfn (Of T1 [ , T2 … ] ) ( item1 [ , item2 … ] )

tuple.Itemk

n
The number of items, 1 to 7. Each number has a class of its own, from TupleOf1 to TupleOf7.
T1, T2 …
The types of the items, one for each item, in order. All n must be given. Types of the items lists the types that work.
item1, item2 …
required The values of the items, one for each type, in the same order. The parameters are ByRef; see Creating a tuple.
tuple
An object expression that evaluates to a tuple.
k
The number of an item, 1 to n.

Itemk returns the kth item, of type Tk. The properties are read-only: an item is set only when the tuple is created, and nothing changes it afterwards. The classes have no other members.

Class Type parameters Properties
TupleOf1 T1 Item1
TupleOf2 T1, T2 Item1, Item2
TupleOf3 T1 to T3 Item1 to Item3
TupleOf4 cannot be used; see TupleOf4  
TupleOf5 T1 to T5 Item1 to Item5
TupleOf6 T1 to T6 Item1 to Item6
TupleOf7 T1 to T7 Item1 to Item7

There is no class for eight or more items. The package’s source holds one, TupleOfN, as comments only.

Creating a tuple

New creates a tuple and passes the items to the class’s constructor. The As New form of Dim takes no arguments, so a tuple is created with New and assigned to a variable declared with the tuple’s type:

Dim size As TupleOf2(Of Long, Long)
Set size = New TupleOf2(Of Long, Long)(640, 480)
Debug.Print size.Item1 * size.Item2  ' 307200

A function that returns a tuple declares the tuple’s type as its return type:

Module GenericsMinMaxDemo
    ' Returns the smallest and the largest value of an array.
    Public Function MinMax(values() As Double) As TupleOf2(Of Double, Double)
        Dim lo As Double = values(LBound(values))
        Dim hi As Double = lo
        Dim i As Long
        For i = LBound(values) + 1 To UBound(values)
            If values(i) < lo Then lo = values(i)
            If values(i) > hi Then hi = values(i)
        Next
        Return New TupleOf2(Of Double, Double)(lo, hi)
    End Function

    Public Sub Report()
        Dim data(2) As Double
        data(0) = 4.5
        data(1) = -2
        data(2) = 9
        Dim r As TupleOf2(Of Double, Double) = MinMax(data)
        Debug.Print "Smallest:"; r.Item1; " Largest:"; r.Item2
    End Sub
End Module

Note

In BETA 1005, New with a generic class from a package compiles only when some declaration in the project or the package names the same class with the same type arguments. A variable declared with the tuple’s type is such a declaration. Without one, Dim t As Any = New TupleOf2(Of String, Long)("a", 2) fails with TB5074, Could not bind to parameterized constructor of class ‘TupleOf2’, and so does New assigned to an Object or Variant variable or passed as an argument. A generic class declared in the project’s own code is not affected. Assign the tuple to a variable of its own type first; that variable can then be assigned to an Object or Variant variable, through which the items are read late-bound:

Dim t As TupleOf2(Of String, Long) = New TupleOf2(Of String, Long)("width", 640)
Dim o As Object
Set o = t
Debug.Print o.Item1; o.Item2  ' width 640

The constructor’s parameters are declared without ByVal, so they are ByRef. A variable passed for an item must have the item’s type exactly: a Byte variable passed for a Long item fails with TB5001, cannot coerce type ‘Byte’ to [ByRef] ‘Long’. A literal or any other expression is converted as usual, so wrap such a variable in a conversion function. The tuple keeps a copy of each value, and a later change to the variable does not change the tuple:

Dim b As Byte = 200
Dim t As TupleOf1(Of Long) = New TupleOf1(Of Long)(CLng(b))
b = 1
Debug.Print t.Item1  ' 200

Reading the items

Each item is read through its Item property, which returns it with the type it was declared with. A tuple is an object, so it is assigned with Set, and a variable that has not been assigned one is Nothing. Two tuples with equal items are still two objects: Is compares the objects themselves, so the items are compared one by one. TypeName returns the class’s name without its type arguments:

Dim a As TupleOf2(Of Long, String) = New TupleOf2(Of Long, String)(1, "x")
Dim b As TupleOf2(Of Long, String) = New TupleOf2(Of Long, String)(1, "x")
Debug.Print TypeName(a)                              ' TupleOf2
Debug.Print a Is b                                   ' False
Debug.Print a.Item1 = b.Item1 And a.Item2 = b.Item2  ' True

Unlike .NET’s tuples, the classes have no method that compares two tuples or converts one to a string.

Types of the items

An item can have any numeric type, String, Boolean, Date, Currency or LongPtr. Three kinds of type cannot be used:

  • Variant. twinBASIC refuses Variant as a type argument: TB5124, Cannot pass Variant datatype as a generic specifier, use a more explicit type instead.
  • Object types. The constructor stores each item with =, not with Set. A class whose default member takes an argument, such as Collection, fails to compile, with TB5092 Missing argument ‘Index’ reported in the package’s source. Object compiles, but creating the tuple raises run-time error 91, Object variable or With block variable not set, even when the item passed is Nothing. So a tuple cannot hold another tuple either.
  • Arrays, such as Long().

TupleOf4

Note

TupleOf4 cannot be used in version 1.0.0.0. The package declares it with three type parameters, TupleOf4(Of T1, T2, T3), but its fourth item uses a fourth, T4, which is not declared. With four type arguments, a declaration fails with TB5124, Too many generic specifiers. With three, the package’s source fails with TB5079, Unrecognized datatype symbol ‘T4’. A project that does not use TupleOf4 is not affected. For four values, use TupleOf5 and leave its last item unused.

See Also

  • Generics – generic classes, procedures and types in twinBASIC
  • Parameterized class constructors – the Sub New that each tuple class declares
  • New operator – creates an object, passing arguments to its constructor