Description
All types are implemented as hash tables. Most types are mutable, so that additional methods for handling their instances can be added at any time. However, if a type has an ancestor where the methods can be stored, then mutability is not needed.
When a type is used to represent a mathematical object, then immutability is desirable, in order to make the strict equality operator work on it. For example, a module
M is a type, with its elements are its instances, but we would like to be able to compare two modules quickly, and form sets of modules. This is possible, because we have implemented modules as immutable types, and we have put the methods for adding and subtracting elements of
M into the class
Vector.
i1 : F = ZZ^3
3
o1 = ZZ
o1 : ZZ-module, free
|
i2 : class F
o2 = Module
o2 : Type
|
i3 : parent class F
o3 = ImmutableType
o3 : Type
|
i4 : showStructure class F
o4 = Thing : HashTable : ImmutableType : Module
o4 : Descent
|
i5 : showStructure F
o5 = Thing : BasicList : Vector : F
o5 : Descent
|
i6 : v = F_0 + 3*F_2
o6 = | 1 |
| 0 |
| 3 |
3
o6 : ZZ
|
i7 : F === ZZ^3
o7 = true
|
i8 : set (ZZ^3, ZZ^2, ZZ^3)
2 3
o8 = set {ZZ , ZZ }
o8 : Set
|
i9 : peek F
o9 = Module of Vector{cache => CacheTable{...2...} }
numgens => 3
RawFreeModule => free(rank 3 degrees = {1, 1, 1})
ring => ZZ
|
Another advantage of immutability of modules is that there is no particular reason, aside from efficiency, to avoid creating a given module multiple times, as one copy of the module is as good as another.
i10 : ZZ^3_0 + ZZ^3_2
o10 = | 1 |
| 0 |
| 1 |
3
o10 : ZZ
|