Is there a default initializer that is called when an object is constructed and that can be overloaded?
I have a chicken and egg problem about initializing a generic data structure.
In data structure module1.nim, I need to initialize a generic parameter and I forward declare the initElement[T]: T proc so that a data structure can call it and the client using that module will be able to initialize her objects:
type
MyType[T] = object
... complex data structure...
# Forward initializer
proc initElement*[T]: T
proc foo[T]: T =
# Here I need to initialize T
result = initElement[T]()
... do something on T
In client module, where T is instantiated, the client must define the initElement: TypeInstance proc but the compiler now says that overloaded 'initElement' leads to ambiguous calls:
import module1
type
TypeInstance = object
... complex type that must be initialized
proc initElement: TypeInstance =
# Initialize correctly the type
result = doCalculations()
Is there a pattern in order to delegate initialization to the user of a module? A bit like when using Table[K, V], the client must define hash and == for the key type.
I could require passing a proc pointer to the initializer in the generic module, but I would like to use naming/overloading resolution instead as the interface will be simpler for the clients.
Initializing objects are required when defaults values are not acceptable and create invalid objects. For instance, when default values are the result of complex calculations, or simply when '\0' is not valid default character.
I've tried using concepts too but did not got a correct result.
Sorry, but I don't understand how it applies.
My generic module defines a general behaviour, just like a generic container, and the instance module instantiates that behaviour but must complement a specific part (initialization), just like some containers require generic parameters to implement some procs.
If I understand you correctly, you wanted the client/user of the module to provide their own initElement proc of their type, didn't you?
In that case, you're able to ensure the compiler to check whether the user provide their own initElement using compile proc.
proc foo[T]: T =
when not compiles(initElement[T]()):
{.error: "please provide initElement proc for your type".}
result = initElement[T]()
If I understand you correctly, you wanted the client/user of the module to provide their own initElement proc of their type, didn't you?
Yes
In that case, you're able to ensure the compiler to check whether the user provide their own initElement using compile proc.
The problem is not so much with telling the client to define initElement in his code. But for the compiler to link all definitions of that proc that are spread between the generic module and the client module, with overloading.
I've tried to reproduce the problem in the playground.
I have to provide an initElement proc in the generic module in order to compile foo[T] (line #10). That's the reason there's a forward declaration of initElement (line #7).
The problem occurs when the client defines initElement in his code (line #30). The compiler complains that Error: overloaded 'initElement' leads to ambiguous calls when the client wants to call the foo proc from the generic module (line #37).
I have to provide an initElement proc in the generic module in order to compile foo[T] (line #10). That's the reason there's a forward declaration of initElement (line #7).
I tried your code, removed the forward-declaration and fixed your initElement definition and it's working fine.
proc initElement[T: TypeInstance]: T =
result.c = 'E'
discard foo[TypeInstance]()
I tried with compile proc and tried to call with discard foo[int]() and the compiler throw out error with error message supplied to error pragma.
Try it.
Thanks mashigan.
If I understand correctly, the Error: overloaded 'initElement' leads to ambiguous calls message was created because the initElement proc signature in the client module in the original code was not exactly the same as the one used in the generic module.
For future reference, I've change the playground example with the final syntax.
Now I just have to apply it in my code...
Error: overloaded 'initElement' leads to ambiguous calls
You tried to overload using generic but actually proc overload usually done with argument types. When you defined generic, it's actually creating overload proc based on argument type, for example
proc add[T: SomeInteger](a, b: T): T =
a + b
discard add(4'u32, 5'u32)
discard add(4'i32, 5'i32)
would actually have
proc add(a, b: uint32): uint32 = a + b
proc add(a, b: int32): int32 = a + b
CMIIW