.new accepts positional and keyword args, and converts positional to keyword, and passes them to #initialize
#initialize accepts only keyword arguments, and is easy to redefine for custom processing; the default implementation has all keyword arguments mandatory.
If .new method would be implemented in Ruby, for Data.define(:a, :b) it'll look this way:
KEYS=[:a,:b]defself.new(*args,**kwargs)# raise if both args and kwargs provided# handle argsifargs.any?raiseArgumentErrorifargs.size>KEYS.sizekwargs=args.zip(KEYS).to_h{|value,name|[name,value]}endallocate.initialize(**kwargs)end
It other words:
for .new, any number of positional args is correct, as long as it has names for them
they are converted to keyword args, and passed to initialize
...which will raise if something is missing in the default implementation, but this implementation can be redefined without .new thinking about it