Skip to content

Commit

Permalink
Destructors
Browse files Browse the repository at this point in the history
  • Loading branch information
jjv360 committed Mar 8, 2023
1 parent c04da62 commit 8248970
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 32 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class Shape:
method init() =
echo "Creating a Shape"
## Optional destructor (not implemented yet)
method destroy() =
## Optional destructor (not supported in JS)
method deinit() =
echo "Destroying a Shape"
## Abstract draw function
Expand Down
2 changes: 1 addition & 1 deletion classes.nimble
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Package
version = "0.2.15"
version = "0.3.16"
author = "jjv360"
description = "Adds class support to Nim."
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/classes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ./classes/plugin_super
import ./classes/plugin_meta
import ./classes/plugin_mixins
import ./classes/plugin_singleton
# import ./classes/plugin_destructors
import ./classes/plugin_destructors
export static

## Class definition
Expand Down
10 changes: 6 additions & 4 deletions src/classes/plugin_destructors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ proc generateDestructor(classDef : ClassDescription) =
if not m.existsIn(classDef):
return

# It exists, add destroy method
let thisName = ident"this"
# It exists, add destroy proc.
# Note: The way this works is that we receive a reference to the actual underlying object, unwrapped from
# any refs. So we need to wrap it again for the final deinit call.
let methodName = parseExpr("`=destroy`")
let className = classDef.name
classDef.outputBody.insert(0, quote do:
proc `methodName`*(`thisName`: var typeof(`className`()[])) =
`thisName`.deinit()
proc `methodName`*(thisRaw: var typeof(`className`()[])) =
var this : `className` = cast[`className`](thisRaw.addr)
this.deinit()
)


Expand Down
64 changes: 40 additions & 24 deletions test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ else:
# Native code
import asyncdispatch
import terminal
import os
import times

const platformName = "native"

Expand Down Expand Up @@ -108,7 +110,7 @@ assert(externalGetterSetter.testCustomSetter == 8)



group "Constructors"
group "Constructors and destructors"
test "Automatic constructors on the base class"
class ClassA

Expand Down Expand Up @@ -211,33 +213,47 @@ class ClassWithFactory:
assert(ClassWithFactory.withValue(3).v1 == 3)


test "Destructor called"
test "Destructors"

# # Counter to store destructor call count
# var globalDestructorCounter = 1

# # Simple destructor
# class TestDestructor1:
# method deinit() = globalDestructorCounter += 1

# # Class with destructor in the superclass
# class TestDestructor2 of TestDestructor1
when defined(js):

# # Class with custom destructor
# class TestDestructor3 of TestDestructor1:
# method deinit() =
# super.deinit()
# globalDestructorCounter += 1 # <-- Add again
# Not supported
warn "Not supported in Javascript"

# # Run all destructors
# proc checkDestructor() =
# let cls = TestDestructor1.init() # <-- Destructor adds one
# discard TestDestructor2.init() # <-- Destructor in superclass adds one
# discard TestDestructor3.init() # <-- Destructor adds one + calls super destructor which also adds one
# checkDestructor()
else:

# # Ensure the counter is correct
# assert(globalDestructorCounter == 5)
# Counter to store destructor call count
var globalDestructorCounter = 1

# Simple destructor
class TestDestructor1:
method deinit() = globalDestructorCounter += 1

# Class with destructor in the superclass
class TestDestructor2 of TestDestructor1

# Class with custom destructor
class TestDestructor3 of TestDestructor1:
method deinit() =
super.deinit()
globalDestructorCounter += 1 # <-- Add again

# Create objects to be cleaned up
proc checkDestructor() =
let cls = TestDestructor1.init() # <-- Destructor adds one
let cls2 = TestDestructor2.init() # <-- Destructor in superclass adds one
let cls3 = TestDestructor3.init() # <-- Destructor adds one + calls super destructor which also adds one
checkDestructor()

# GC takes a while, wait for it to be done
let startedAt = cpuTime()
while true:
if globalDestructorCounter == 5 or startedAt - cpuTime() > 10: break
GC_fullCollect()
sleep(100)

# Ensure the counter is correct
assert(globalDestructorCounter == 5, "Expected 5 but got " & $globalDestructorCounter)



Expand Down

0 comments on commit 8248970

Please sign in to comment.