Yes, you are right :-(. I forgot your requirement. I fear there is no simple solution in this case, as you need to create the object with the right type (to get the right size) and, at this moment, you don’t have access to the private field. In fact, I’m sure that my first solution with a cast doesn’t work if extra fields exists in _ElementA_ (it compiles, but will cause problems at runtime).
And I’m not sure that using a macro will change anything: you need to allocate in the client module to get the right size and to allocate in the _lib_ module to have access to the private field. This is incompatible. But there are ways to check that _initElement_ is not called several times. For instance, you can add a private boolean field _initialized_ in _Element_ which is false by default. Then _initElement_ becomes: proc initElement(elem: Element, id: string) = if elem.initialized: # already initialized: raise some exception … elem.id = id elem.initialized = true Run Or, if you require that _id_ cannot be the empty string, you no longer need the _initialized_ field: proc initElement(elem: Element, id: string) = if id.len == 0: # id must not be empty: raise some exception. … if elem.id.len != 0: # already initialized: raise some other exception. … elem.id = id Run I agree that these are not very elegant solutions. Maybe using a macro to initialize could solve the problem in a more elegant way. I can’t say for sure as I have not use macros for now.