Hi there,
I am creating an observer for a relatively large data structure. I want to be able to access the data without immediately updating all subscribers, so a read-only access. Currently there are two approaches:
Create a pass-by. Simply give full access to the data without updating afterwards. This is not optimal, since I want to have an explicit difference between mutable and immutable access.
Simply copy the data. You can still change the copy, but this won't affect the real data. Not optimal either, since I'd be copying large amounts of data.
My question is, is there an immutable pointer in nim? If there isn't, can I create one? I have seen a thread from 4 years ago where the idea of explicit mutable and immutable types, like in rust, was passed around. This would be perfect, but I don't think it was ever implemented.
you can do something like this:
type
ImmutableWhatever = ref object of RootObj
iAmImmutableData: int
iAmImmutableToo: string
MutableWhatever = ref object of ImmutableWhatever
# getter
proc iAmImmutableData(self: ImmutableWhatever): int = self.iAmImmutableData
proc iAmImmutableToo(self: ImmutableWhatever): string = self.iAmImmutableToo
# setter only for the mutable version
proc `iAmImmutableData=`(self: ImmutableWhatever, val: int) = self.iAmImmutableData = val
proc `iAmImmutableToo=`(self: ImmutableWhatever, val: string)= self.iAmImmutableToo = val
is there an immutable pointer in nim?
Unfortunately, no.
If there isn't, can I create one?
Yes. That's simple.
type ImmutableObjPtr[T] = distinct ptr T
proc `[]`[T](self: ImmutableObjPtr): T =
result = (ptr T)(self)[]
Therefore assigning to the variable pointed to by an ImmutableObjPtr is not possible, because []= is not implemented.type
LimbsView = ptr UncheckedArray[SecretWord]
## Type-erased fixed-precision limbs
##
## This type mirrors the Limb type and is used
## for some low-level computation API
## This design
## - avoids code bloat due to generic monomorphization
## otherwise limbs routines would have an instantiation for
## each number of words.
##
## Accesses should be done via BigIntViewConst / BigIntViewConst
## to have the compiler check for mutability
# "Indirection" to enforce pointer types deep immutability
LimbsViewConst = distinct LimbsView
## Immutable view into the limbs of a BigInt
LimbsViewMut = distinct LimbsView
## Mutable view into a BigInt
LimbsViewAny = LimbsViewConst or LimbsViewMut
# Deep Mutability safety
# ------------------------------------------------------------
template view(a: Limbs): LimbsViewConst =
## Returns a borrowed type-erased immutable view to a bigint
LimbsViewConst(cast[LimbsView](a.unsafeAddr))
template view(a: var Limbs): LimbsViewMut =
## Returns a borrowed type-erased mutable view to a mutable bigint
LimbsViewMut(cast[LimbsView](a.addr))
template `[]`*(v: LimbsViewConst, limbIdx: int): SecretWord =
LimbsView(v)[limbIdx]
template `[]`*(v: LimbsViewMut, limbIdx: int): var SecretWord =
LimbsView(v)[limbIdx]
template `[]=`*(v: LimbsViewMut, limbIdx: int, val: SecretWord) =
LimbsView(v)[limbIdx] = val