I am converting some Ruby code to Nim and got
proc initialize(s: Step; prev, nxt, id: int) =
s.prev = prev
s.next = next
s.id = id
s.radius = 0 # default for incident net
s.outer = false
The first 3 assignments in the proc are a pattern that occur often in my code, and so since many years I ask myself if it may be possible to have instead something like
proc initialize(s: Step; prev, nxt, id: int) =
s.doTheMagic(prev, next, id)
s.radius = 0 # default for incident net
s.outer = false
or maybe even better but more fragile
proc initialize(s: Step; prev, nxt, id: int) {.magicallyInitializeClassFieldsWithMatchingNames.} =
# s.doTheMagic(prev, next, id)
s.radius = 0 # default for incident net
s.outer = false
Yea, I'm also annoyed with the need to type code twice. Actually it's the types typed twice, the keys typed 4 times, 1) in object definition 2) in init args 3 and 4) in object initialisation as key: key
type HedgedStock* = object
id*: string
evol*: float
safe_mv*: float
min_tenor*: float
min_hedge_mv*: float
stocks*: seq[UStock]
puts*: seq[UOption]
proc init*(
_: type[HedgedStock],
id: string,
evol: float,
safe_mv: float,
min_tenor: float = 120.0,
min_hedge_mv: float = 0.02,
stocks: openarray[UStock],
puts: openarray[UOption]
): HedgedStock =
assert evol > 1.0
HedgedStock(
id: id, evol: evol, safe_mv: safe_mv,
min_tenor: min_tenor, min_hedge_mv: min_hedge_mv,
stocks: stocks.to_seq, puts: puts.to_seq
)
As the author of constructor I really have to agree with the "Oh god it's so tedious to right it so many times" so I solved it. Recently just made my new defaults macro which makes it so you only have to type the definition once! Feast your eyes on macro magic!
import constructor/defaults
type Thingy {.defaults.} = object # Tests the basic operation
a: float = 100
b: string = "Hello world"
implDefaults(Thingy)
assert initThingy() == Thingy(a: 100f, b: "Hello world")
As the author of constructor
Yes, Yardanico already told us.
But from my current understanding your macro currently can initialize objects only with default constants. Which I need rarely as my defaults are generally binary zero. What I sometimes need is initialization with runtime values as in my example above:
proc initialize(s: Step; prev, next, id: int) =
s.prev = prev
s.next = next
s.id = id
s.radius = 0 # default for incident net
s.outer = false
Here Step is an object, and next, prev, id are runtime variables. Id is an integer, and next and prev may be references (I do not know the type, wrote the Ruby code ten years ago, but this detail does not really matter for the concept of initialization.)
The core idea of my initial post was that the parameter names of the runtime initializer proc exactly match the fieldnames of the object to initialize. And that is a pattern which often occurs for me, like student.firstName = firstName. With the std "with" macro we could write firstName = firstName which is still not really nice. I will investigate your macro, maybe I can tune it for my needs.