@Araq, regarding your latest revision to spec 2 regarding "Hook Lifting": 
[https://github.com/nim-lang/Nim/wiki/Destructors,-2nd-edition#id15](https://github.com/nim-lang/Nim/wiki/Destructors,-2nd-edition#id15),
 and "Hook Generation": 
[https://github.com/nim-lang/Nim/wiki/Destructors,-2nd-edition#id16](https://github.com/nim-lang/Nim/wiki/Destructors,-2nd-edition#id16),
 I see that "Hook Lifting" is necessary and is as I implied an a 
"foreshadowing" suggestion somewhere further up this thread, but regarding 
"Hook Lifting":

> Other value-based compound types like object and array are handled 
> correspondingly. For object however, the compiler generated hooks can be 
> overridden...

and regarding "Hook Generation":

> The ability to override a hook leads to a phase ordering problem:...
> 
> The solution is to define proc `=destroy`[T](f: var Foo[T]) before it is 
> used. The compiler generates implicit hooks for all types in strategic 
> places...

Doesn't this start to make us think that there must be a better solution than 
covering all the special cases?

My proposed solution (if I understand it correctly ;-) ) is as follows:

1\. To have "hooks" defined by default for pointer and automatically generate 
"lifting hooks" for every general type class that could be a container as ptr T 
(ref/owned ref already covered in spec 2), tuple, array[T], etc. **ahead of 
time** when the type is defined so that they are automatically available when 
bindings are declared implicitly or explicitly that use those types. These 
default hooks can also be overridden ahead-of-time in which case the default 
hooks wouldn't be used. If this can be done, you can avoid the extra compiler 
logic required to determine where to automatically generate the hook lifting as 
in "strategic places" as the lifted hook already exist as defaults, or if 
specialized behaviour is desired then the default overrides will have already 
been written when the type was defined.

Having the above defaults predefined for specific types such as pointer, ptr T, 
and UncheckedArray{T} would prevent memory leaks as in forgetting to deallocate 
as follows: 
    
    
    # default hooks...
    template `=destroy`{T](ua: UncheckedArray[T]) =
      let uap = cast[pointer](`ua`)
      if uap!= nil: uap.dealloc; `ua`.unsafeAddr[] = nil
    template `=`[T](dst, src: UncheckedArray[T]) =
      let dstp = cast[pointer](`dst`); let srcp = cast[pointer](`src`)
      if dstp != srcp: `=destroy`(`dst`); `dst`.unsafeAddr[] = 
`src`.unsafeAddr[]
    template `=move`[T](dst, src: UncheckedArray[T]) =
      let dstp = cast[pointer](`dst`); let srcp = cast[pointer](`src`)
      if dstp != srcp: `=`(`dst`, `src`); `src`.unsafeAddr[] = nil
    
    # now the following will be automatically deallocated at the end of scope...
    var myua = cast[UncheckedArra[int]](int.sizeof.alloc)
    
    
    Run

Obviously it isn't a safe system as it doesn't have the checks of a ref/owned 
ref to prevent deallocation too soon when there is more than one copy and one 
of the copies goes out of scope while others are still in use in which case one 
should be using ref/owned ref, but at least it prevents memory leaks by always 
deallocating at the end of scope.

Having default hooks for every type means that hook generation should not be 
necessary other than exactly when types are defined, and the only extra logic 
would be not to auto generate when there are override hooks for the specific 
type.

2 To make the code more consistent and complete, it should be possible to 
define overrides for any type that may contain elements that could need to be 
destroyed, which would include object as currently but also types that are 
specializations of ptr T, tuple, array[T], UncheckedArray{T], etc. for the same 
reasons as given for object in the "Hook Lifting" section of spec 2:

> This can also be important to use an alternative traversal of the involved 
> datastructure that is more efficient or in order to avoid deep recursions.

Reply via email to