I am attempting to write a proc for [] which handles HSlice.
I am failing to see how to convey to the newSeq the desired T
type MyArray*[T: int|float] = ref object
#Fixed size array type object with state.
values*: seq[T]
size*: int
#...
proc `[]`*[T: int|float](ma: MyArray, hs: HSlice): seq[T] =
result = newSeq[T](hs.b - hs.a + 1)
# ...
# I want to be able to do ...
var ma = newMyArray(...)
let sliceOfMA = ma[5..10]
Any help, wisdom or understanding greatly appreciated.
I do not know what you intent, and I have the feeling that you do not know it as well.
With these fixes your code compiles, but of course it does not work already, you would have to add code, for example for copying the seq elements.
type MyArray*[T: int|float] = ref object
values*: seq[T]
size*: int
proc `[]`*[T: int|float](ma: MyArray[T], hs: HSlice): seq[T] =
result = newSeq[T](hs.b - hs.a + 1)
var ma = MyArray[float]()
let sliceOfMA = ma[5..10]
Some points that makes no sense from your initial example:
Generally, why not start without generics, and add generics later? I did that for my Delaunay triangulation and for my RTree and MinMaxHeap. Starting fully generic is more difficult, but when it works, making it generic is not that difficult in Nim.
I hope you have an understanding why we use generics at all in Nim, it is related to the fact that Nim is a statically typed language. People knowing only dynamically languages like Python often wonder why a seq can not contain floats and ints at the same time. I assume that you know that even with generics a seq contains only ints or only float, but never both. When you define a generic proc, you indeed generate multiple procs, one for the int seq, and one for the float seq.
Thanks for the reply.
I will firmly admit that learning generics is tough. The documentation is slim. And I don't know where a nice set of examples exist. That is why I am pressing through displaying my ignorance and hoping for some help.
My apologies for the very simple sample code. I was trying to provide enough code to convey the problem. But not so much as to bog down in unnecessary information. I will endeavor to provide better examples and sufficient information in the future.
You are correct I did not provide a valid constructor I did not feel it necessary for the question. And yes I do understand that a seq is not fixed sized. But my object is. It will never increase the size of the seq which it contains. The fact that it is a seq is an implementation detail. I would use an array. But I do not have sufficient information at compile time to create an array.
I don't know that there will ever be any users of the slice operation of my object. But I wanted to learn how to do it and code it. I believed it would be another step to understanding generics.
And I was correct. You did provide me with enough information to make it work.
I am writing a trading app. I think Nim is a great language for such an app.
I did not start writing the app in Nim but in Smalltalk. Performance was not the best but sufficient. Stability is what became the problem. When I had an array of 5-100million floats and the memory was 1gb+. I was going to finish the app and get version 1 running. But with the stability problem. I decided to go to what I was going to write version 2 in. It will take me a little longer as I am far and away not as familiar with static typing, static compilation and Nim in general.
In trading you have a continual stream of time series data. Which is a set of values containing (datetime, open, high, low, close) for the specified time period. Then you operate on those values. A common item is a fixed sized slice of the data from the most recent, back a specified number of periods.
Commonly this is done in a multi-dimensional array maintaining a large number of periods of data. And on the column you need a slice of
mydata[latestIndex - numberOfPeriods .. latestIndex].
I have chosen not to go that route but simply maintain only the data which which is necessary for my specific strategy.
For your complete understanding of what I am actually doing. Not a sample. I will provide the complete code below. Should anybody like any of the code. I hereby release it under the MIT license.
The MovingArray below is somewhat like a FIFOQueue that is fixed in size. There may be something out there like this or better than this. I am not an expert in programming or algorithms. So my implementation may be naive or better implementations exist. But I will display my ignorance. I have a lot to learn.
Thanks again.
##MovingArray
##(c) copyright 2019 Jimmie Houchin
##MIT license
type MovingArray*[T: int|float] = ref object
##MovingArray is an array type object with a fixed number of values.
##It maintains a small set of state variables which are update each push()
values*: seq[T]
size*: int
index: int
sum*: T
high*: T
low*: T
proc newMovingArray*[T: int|float](size: int, tp: typedesc[T]): MovingArray[T] =
result = MovingArray[T](
size: size,
values: newSeq[T](size),
sum: 0,
index: size-1,
high: low(T), #guarantees first value will replace initial value
low: high(T) #guarantees first value will replace initial value
)
proc `[]`*(ma: MovingArray, index: int): int|float =
var i = ma.index + index
if i > ma.size-1:
i = i - ma.size
result = ma.values[i]
proc `[]`*[T: int|float](ma: MovingArray[T], hs: HSlice): seq[T] =
result = newSeq[float](hs.b - hs.a + 1)
var index = 0
for i in hs:
result[index] = ma[i]
index += 1
proc push*[T: int | float](ma: MovingArray, n: T): T =
if ma.index == ma.size-1:
ma.index = 0
else:
ma.index += 1
result = ma.values[ma.index]
ma.values[ma.index] = n
ma.sum = ma.sum - result + n
if ma.high < n:
ma.high = n
elif ma.high == result:
ma.high = ma.values.max()
if ma.low > n:
ma.low = n
elif ma.low == result:
ma.low = ma.values.min()
proc avg*(ma: MovingArray): float =
result = ma.sum / ma.size