Skip to content

Commit

Permalink
Remove destructors
Browse files Browse the repository at this point in the history
  • Loading branch information
oprypin committed Dec 6, 2018
1 parent a1c1c41 commit fa756bd
Show file tree
Hide file tree
Showing 18 changed files with 75 additions and 43 deletions.
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,13 @@ nim-csfml
Warning
-------

This library consists of class wrappers implemented as `ptr object`. Because Nim does not allow attaching pointers to the garbage collector, I decided to use [destructors][nim-destructors] hoping that would be a reasonable way to implement automatic disposal of objects. However, this feature is based on lexical scoping, which (as I later realized) makes things problematic: the disposal behavior is more like normal `object`s rather than `ref objects`, and sometimes unpredictable.

It is recommended to disable destructors (pass `-d:csfmlNoDestructors` to the compiler) and dispose of the `ptr object`s manually by calling `destroy`. Standard memory management caveats apply: destroying objects that are still used will break things, forgetting to destroy is a memory leak.

There is no good way to fix this under the current state of the language, short of reimplementing everything with additional wrapper classes which also add a lot of overhead.
This library consists of class wrappers implemented as `ptr object`. Because Nim does not allow attaching pointers to the garbage collector, disposal of objects is not implemented and needs to be manual, by calling the `destroy` methods. Standard memory management caveats apply: destroying objects that are still used will break things, forgetting to destroy is a memory leak.

[More details](https://github.com/BlaXpirit/nim-csfml/issues/6)

This library is not under active development, but detailed bug reports will be given proper attention.




Introduction
------------

Expand All @@ -29,7 +23,7 @@ The API attempts to be very similar to SFML's, but some general changes are pres

- To construct an object (`sf::SomeType x(param)`), use a corresponding procedure (there are 2 variations):
- `var x = newSomeType(param)`, which means it is a `ptr object`.
- Such objects have [destructors][nim-destructors] associated with them (no need to call `destroy` manually).
- Such objects need to have `destroy` called to properly dispose of them.
- Never create them using `new`.
- `var x = someType(param)`, which means it is an `object` (in CSFML it corresponds to a simple `struct`).
- `Vector2(i|f)`, `Vector3f` and `(Int|Float)Rect` should be created using special `vec2`, `vec3` and `rect` procs.
Expand Down Expand Up @@ -102,7 +96,6 @@ This library uses and is based on [SFML][] and [CSFML][].
[csfml]: http://www.sfml-dev.org/download/csfml/
[sfml-tutorials]: http://www.sfml-dev.org/tutorials/
[nim]: http://nim-lang.org/
[nim-destructors]: http://nim-lang.org/docs/manual.html#type-bound-operations-destructors
[python]: http://python.org/
[nimble]: https://github.com/nim-lang/nimble
[nimrod-sfml]: https://github.com/fowlmouth/nimrod-sfml
4 changes: 4 additions & 0 deletions examples/flippy_bird.nim
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ while window.open:
window.draw bird

window.display()

bird.destroy()
bird_texture.destroy()
window.destroy()
4 changes: 3 additions & 1 deletion examples/gl.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ while window.open:
glColor3f(0.0, 0.5, 1.0); glVertex2f( 0.0, -1.0)
glEnd()

window.display()
window.display()

window.destroy()
11 changes: 11 additions & 0 deletions examples/pong.nim
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,14 @@ while window.open:

# Display things on screen
window.display()

clock.destroy()
AITimer.destroy()
pauseMessage.destroy()
font.destroy()
ball.destroy()
rightPaddle.destroy()
leftPaddle.destroy()
ballSound.destroy()
ballSoundBuffer.destroy()
window.destroy()
9 changes: 9 additions & 0 deletions examples/shader.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,12 @@ while window.open:
window.draw text, renderStates(shader=wbShader)

window.display()

clock.destroy()
window.destroy()
wbShader.destroy()
text.destroy()
font.destroy()
pxShader.destroy()
sprite.destroy()
texture.destroy()
5 changes: 5 additions & 0 deletions examples/shapes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ while window.open:
vertexArray.append vertex(vec2(100, 0), Red)
vertexArray.append vertex(vec2(0, 100), Blue)
window.draw vertexArray
vertexArray.destroy()

# Top right
var vertexSeq = @[
Expand All @@ -38,6 +39,7 @@ while window.open:
convexShape[2] = vec2(0, 100)
convexShape.fillColor = Green
window.draw convexShape
convexShape.destroy()

# Bottom right
proc getPointCount(p: pointer): int {.cdecl.} = 3
Expand All @@ -50,5 +52,8 @@ while window.open:
customShape.update()
customShape.fillColor = Green
window.draw customShape
customShape.destroy()

window.display()

window.destroy()
2 changes: 2 additions & 0 deletions examples/simple.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ while window.open:
if event.kind == EventType.Closed:
window.close()
window.display()

window.destroy()
6 changes: 6 additions & 0 deletions examples/snakes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ proc draw[T](self: Food, target: T, states: RenderStates) =
circle.position = vec2(self.position)+vec2(0.05, 0.05)
circle.fill_color = self.color
target.draw circle, states
circle.destroy()



Expand Down Expand Up @@ -107,6 +108,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) =
segment.position = vec2(current)+vec2(0.05, 0.05)
segment.fill_color = self.color
target.draw segment, states
segment.destroy()

# The following is eye candy and may be removed
# but change the above to RectangleShape of size (0.9, 0.9)
Expand All @@ -124,6 +126,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) =
connection.position = vec2(current)+vec2(float(d.x)/2.0+0.05, float(d.y)/2.0+0.05)
connection.fill_color = self.color
target.draw connection, states
connection.destroy()

# Draw eyes with a darkened color
var eye = new_CircleShape(radius=0.2/2)
Expand All @@ -136,6 +139,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) =
eye.position = self.body[0]+vec2(0.4, 0.4)-delta
target.draw eye, states

eye.destroy()


proc new_Field(size: Vector2i): Field =
Expand Down Expand Up @@ -222,3 +226,5 @@ while window.open:
window.draw field, states

window.display()

window.destroy()
2 changes: 2 additions & 0 deletions examples/sound_capture.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ else:
while sound.status == SoundStatus.Playing:
echo "Playing... ", sound.playingOffset.asSeconds, " sec"
sleep 100.milliseconds
sound.destroy()

recorder.destroy()
echo "Done!"
3 changes: 2 additions & 1 deletion examples/test_graphics.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ block:
let s = "Випробування"
var txt = newText()
txt.str = s
assert txt.str == s
assert txt.str == s
txt.destroy()
1 change: 1 addition & 0 deletions examples/test_system.nim
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ block:
assert t2 > 50000
assert t2 < 150000

clock.destroy()
4 changes: 4 additions & 0 deletions examples/typing.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,7 @@ while window.open:
window.clear White
window.draw text
window.display()

text.destroy()
font.destroy()
window.destroy()
2 changes: 0 additions & 2 deletions generate/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,6 @@ def handle_function(main, params):
main_sgn = 'proc {nfname}{public}({sparams}): {nftype}'
main_fn = '{nfname}'
pragmas = []
if nfname=='destroy':
pragmas.append('destroy')
if nfname.startswith('get') and nfname[3].isupper() and len(params)==1:
nfname = nfname[3].lower()+nfname[4:]
elif nfname.startswith('is') and nfname[2].isupper() and len(params)==1:
Expand Down
12 changes: 6 additions & 6 deletions src/csfml/private/audio_gen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ proc newMusic*(stream: var InputStream): Music {.
## *Returns:* A new Music object (NULL if failed)

proc destroy*(music: Music) {.
destroy, cdecl, importc: "sfMusic_destroy".}
cdecl, importc: "sfMusic_destroy".}
## Destroy a music
##
## *Arguments*:
Expand Down Expand Up @@ -427,7 +427,7 @@ proc copy*(sound: Sound): Sound {.
## *Returns:* A new Sound object which is a copy of ``sound``

proc destroy*(sound: Sound) {.
destroy, cdecl, importc: "sfSound_destroy".}
cdecl, importc: "sfSound_destroy".}
## Destroy a sound
##
## *Arguments*:
Expand Down Expand Up @@ -745,7 +745,7 @@ proc copy*(soundBuffer: SoundBuffer): SoundBuffer {.
## *Returns:* A new SoundBuffer object which is a copy of ``soundBuffer``

proc destroy*(soundBuffer: SoundBuffer) {.
destroy, cdecl, importc: "sfSoundBuffer_destroy".}
cdecl, importc: "sfSoundBuffer_destroy".}
## Destroy a sound buffer
##
## *Arguments*:
Expand Down Expand Up @@ -834,7 +834,7 @@ proc newSoundBufferRecorder*(): SoundBufferRecorder {.
## *Returns:* A new SoundBufferRecorder object (NULL if failed)

proc destroy*(soundBufferRecorder: SoundBufferRecorder) {.
destroy, cdecl, importc: "sfSoundBufferRecorder_destroy".}
cdecl, importc: "sfSoundBufferRecorder_destroy".}
## Destroy a sound buffer recorder
##
## *Arguments*:
Expand Down Expand Up @@ -911,7 +911,7 @@ proc newSoundRecorder*(onStart: SoundRecorderStartCallback, onProcess: SoundReco
## *Returns:* A new SoundRecorder object (NULL if failed)

proc destroy*(soundRecorder: SoundRecorder) {.
destroy, cdecl, importc: "sfSoundRecorder_destroy".}
cdecl, importc: "sfSoundRecorder_destroy".}
## Destroy a sound recorder
##
## *Arguments*:
Expand Down Expand Up @@ -1054,7 +1054,7 @@ proc newSoundStream*(onGetData: SoundStreamGetDataCallback, onSeek: SoundStreamS
## *Returns:* A new SoundStream object

proc destroy*(soundStream: SoundStream) {.
destroy, cdecl, importc: "sfSoundStream_destroy".}
cdecl, importc: "sfSoundStream_destroy".}
## Destroy a sound stream
##
## *Arguments*:
Expand Down
6 changes: 0 additions & 6 deletions src/csfml/private/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@

{.deadCodeElim: on.}

when defined(csfmlNoDestructors):
{.pragma: destroy.}
else:
{.experimental.}
{.pragma: destroy, override.}


when defined(windows):
const lib = "csfml-" & module & "-2.dll"
Expand Down
30 changes: 15 additions & 15 deletions src/csfml/private/graphics_gen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ proc copy*(shape: CircleShape): CircleShape {.
## *Returns:* Copied object

proc destroy*(shape: CircleShape) {.
destroy, cdecl, importc: "sfCircleShape_destroy".}
cdecl, importc: "sfCircleShape_destroy".}
## Destroy an existing circle Shape
##
## *Arguments*:
Expand Down Expand Up @@ -735,7 +735,7 @@ proc copy*(shape: ConvexShape): ConvexShape {.
## *Returns:* Copied object

proc destroy*(shape: ConvexShape) {.
destroy, cdecl, importc: "sfConvexShape_destroy".}
cdecl, importc: "sfConvexShape_destroy".}
## Destroy an existing convex Shape
##
## *Arguments*:
Expand Down Expand Up @@ -1132,7 +1132,7 @@ proc copy*(font: Font): Font {.
## *Returns:* Copied object

proc destroy*(font: Font) {.
destroy, cdecl, importc: "sfFont_destroy".}
cdecl, importc: "sfFont_destroy".}
## Destroy an existing font
##
## *Arguments*:
Expand Down Expand Up @@ -1315,7 +1315,7 @@ proc copy*(image: Image): Image {.
## *Returns:* Copied object

proc destroy*(image: Image) {.
destroy, cdecl, importc: "sfImage_destroy".}
cdecl, importc: "sfImage_destroy".}
## Destroy an existing image
##
## *Arguments*:
Expand Down Expand Up @@ -1468,7 +1468,7 @@ proc copy*(shape: RectangleShape): RectangleShape {.
## *Returns:* Copied object

proc destroy*(shape: RectangleShape) {.
destroy, cdecl, importc: "sfRectangleShape_destroy".}
cdecl, importc: "sfRectangleShape_destroy".}
## Destroy an existing rectangle shape
##
## *Arguments*:
Expand Down Expand Up @@ -1834,7 +1834,7 @@ proc newRenderTexture*(width: cint, height: cint, depthBuffer: BoolInt): RenderT
## *Returns:* A new RenderTexture object, or NULL if it failed

proc destroy*(renderTexture: RenderTexture) {.
destroy, cdecl, importc: "sfRenderTexture_destroy".}
cdecl, importc: "sfRenderTexture_destroy".}
## Destroy an existing render texture
##
## *Arguments*:
Expand Down Expand Up @@ -2152,7 +2152,7 @@ proc newRenderWindow*(handle: WindowHandle, settings: ContextSettings): RenderWi
newRenderWindow(handle, Csettings)

proc destroy*(renderWindow: RenderWindow) {.
destroy, cdecl, importc: "sfRenderWindow_destroy".}
cdecl, importc: "sfRenderWindow_destroy".}
## Destroy an existing render window
##
## *Arguments*:
Expand Down Expand Up @@ -2677,7 +2677,7 @@ proc newShader*(vertexShaderStream: var InputStream, fragmentShaderStream: var I
## *Returns:* A new Shader object, or NULL if it failed

proc destroy*(shader: Shader) {.
destroy, cdecl, importc: "sfShader_destroy".}
cdecl, importc: "sfShader_destroy".}
## Destroy an existing shader
##
## *Arguments*:
Expand Down Expand Up @@ -2896,7 +2896,7 @@ proc newShape*(getPointCount: ShapeGetPointCountCallback, getPoint: ShapeGetPoin
## *Returns:* A new Shape object

proc destroy*(shape: Shape) {.
destroy, cdecl, importc: "sfShape_destroy".}
cdecl, importc: "sfShape_destroy".}
## Destroy an existing shape
##
## *Arguments*:
Expand Down Expand Up @@ -3239,7 +3239,7 @@ proc copy*(sprite: Sprite): Sprite {.
## *Returns:* Copied object

proc destroy*(sprite: Sprite) {.
destroy, cdecl, importc: "sfSprite_destroy".}
cdecl, importc: "sfSprite_destroy".}
## Destroy an existing sprite
##
## *Arguments*:
Expand Down Expand Up @@ -3512,7 +3512,7 @@ proc copy*(text: Text): Text {.
## *Returns:* Copied object

proc destroy*(text: Text) {.
destroy, cdecl, importc: "sfText_destroy".}
cdecl, importc: "sfText_destroy".}
## Destroy an existing text
##
## *Arguments*:
Expand Down Expand Up @@ -3904,7 +3904,7 @@ proc copy*(texture: Texture): Texture {.
## *Returns:* Copied object

proc destroy*(texture: Texture) {.
destroy, cdecl, importc: "sfTexture_destroy".}
cdecl, importc: "sfTexture_destroy".}
## Destroy an existing texture
##
## *Arguments*:
Expand Down Expand Up @@ -4068,7 +4068,7 @@ proc copy*(transformable: Transformable): Transformable {.
## *Returns:* Copied object

proc destroy*(transformable: Transformable) {.
destroy, cdecl, importc: "sfTransformable_destroy".}
cdecl, importc: "sfTransformable_destroy".}
## Destroy an existing transformable
##
## *Arguments*:
Expand Down Expand Up @@ -4233,7 +4233,7 @@ proc copy*(vertexArray: VertexArray): VertexArray {.
## *Returns:* Copied object

proc destroy*(vertexArray: VertexArray) {.
destroy, cdecl, importc: "sfVertexArray_destroy".}
cdecl, importc: "sfVertexArray_destroy".}
## Destroy an existing vertex array
##
## *Arguments*:
Expand Down Expand Up @@ -4363,7 +4363,7 @@ proc copy*(view: View): View {.
## *Returns:* Copied object

proc destroy*(view: View) {.
destroy, cdecl, importc: "sfView_destroy".}
cdecl, importc: "sfView_destroy".}
## Destroy an existing view
##
## *Arguments*:
Expand Down
Loading

0 comments on commit fa756bd

Please sign in to comment.