I work in HPC myself (mostly using Fortran). I liked your slides very much.
However I have a few a few questions. For now, I'll focus on the one that
puzzles me the most.
Am I misunderstanding the purpose of your ArrayObj type? It seems to me your
implementation of macro indexArray*(x: ArrayObj{call}, y: ArrayIndex): untyped
is little inflexible. After all, not every function returning an ArrayObj will
be just doing element-wise calculations (or should it?)... I guess that's a
good time for using procedure-modifying macros which would add them to some
compile-time collection and then indexArray will choose the right
transformation based on data in the collection (also at compile-time). Also,
some special cases could be done easier this way. For example, let's consider
the difference between element-wise addition and multiplication and circular
shifting:
proc `+`*(x: ArrayObj, y: ArrayObj): ArrayObj {.elemental.}
proc `*`*(x: ArrayObj, y: ArrayObj): ArrayObj {.elemental.}
# (x + y * z)[i] --> x[i] + y[i] * z[i]
replace:
proc rshift*(x: ArrayObj, shift: int): ArrayObj = ...
proc opt(x: ArrayObj, shift: int, i: SomeInteger) =
if shift + i < x.len:
x[shift + i - x.len]
else:
x[shift + i]
proc opt(x: ArrayObj, shift: static[int], i: static[SomeInteger]) =
when shift + i < x.len:
x[shift + i - x.len]
else:
x[shift + i]
...
# if x.len == 10:
# x.cshift(2)[5] --> x[6]
# x.cshift(2)[9] --> x[1]
Actually, macro elemental is quite simple. Unless we would like it to use
vectorization or other additional optimizations, of course.