Nim - create a sequence of objects that implement a method

I want to program the game and would like to use the component template for several objects.

In a language with interfaces / types / multiple inheritance there will be no problems.

I want some objects to be updatable but not displayable, and some should be both.


Haskell:

class Updateable a where update :: Float -> a -> a class Renderable a where render :: a -> Picture class InputHandler a where handleInput :: Event -> a -> a 

I can create a list of things that can be updated.

 updateAll :: Updateable a => Float -> [a] -> [a] updateAll delta objs = map (update delta) objs 

In Java / D / ... this can be implemented via interfaces

 interface Updateable { void update(float delta); } // somewhere in a method List<Updateable> objs = ...; for (Updateable o : objs) { o.update(delta); } 

Now I am wondering how this can be implemented in nim using multimethods.

Can the existence of a suitable multimethod be expressed in type?

 var objs: seq[???] = @[] 



Edit: added one more code and fixed incorrect Haskell example
+5
source share
2 answers

I'm not sure if this answers your question, but worth mentioning.

If you intend to store game objects in separate lists based on type, you can still write a lot of common logic. Object storage by type has the best better performance due to read and branch prediction. See this lecture from a guy who needs to know what he is talking about: Multiprocessor game cycles: Uncharted 2: Among Thieves lessons .

For example, if you have defined texture proc for some types of objects, you can write general draw(t: T) = magicRenderToScreen(texture(t)) proc, which will work for all of them. This is also useful if you are really using resource pools or some general behavior.

You need to include any affected type of object in the render and update cycles, but this is usually not very important in practice. You can even use a simple macro to make it less verbose, so your render cycle just contains something like renderAll(players, enemies, sprites, tiles)

Shared lists are not direct in compiled languages, and nim makes you see this, which is good when you are working on a game. To have shared lists, you usually need to use pointers and dynamic dispatch or some type of union. I seem to remember that nim used to send the correct multi-methods from the parent ref object (which would allow lists to contain several types and dynamically send them at runtime), but I'm honestly not sure if this can be done ...?

Someone more knowledgeable, please let us know!

+3
source

The lack of an explicit keyword keyword interface common issue in the Nim community . By taking Araq and applying it to a hypothetical case based on your Java / D snippet, we could write something like this:

 import strutils # For formatFloat type IUpdateable = tuple[ update: proc(v: float) {.closure.}, show: proc(): string {.closure.} ] Rounded = ref object internalValue: float Real = ref object a_real_value: float # Here goes our rounded type. proc `$`(x: Rounded): string = result = "Rounded{" & $int(x.internalValue) & "}" proc updateRounded(x: Rounded, delta: float) = x.internalValue += delta proc getUpdateable(x: Rounded): IUpdateable = result = ( update: proc(v: float) = x.updateRounded(v), show: proc(): string = `$`(x) ) converter toIUpdateable(x: Rounded): IUpdateable = result = x.getUpdateable # Here goes our Real type. proc `$`(x: Real): string = result = "Real{" & x.a_real_value.format_float(precision = 3) & "}" proc update_real(x: Real, delta: float) = x.a_real_value += delta proc getUpdateable(x: Real): IUpdateable = result = ( update: proc(v: float) = x.update_real(v), show: proc(): string = `$`(x) ) # Here goes the usage proc main() = var objs: seq[IUpdateable] = @[] var a = Rounded() var b = Real() a.internalValue = 3.5 b.a_real_value = 3.5 objs.add(a) # works because of toIUpdateable() objs.add(b.getUpdateable) for obj in objs: echo "Going through one loop iteration" echo "\t", obj.show() obj.update(0.4) echo "\t", obj.show() obj.update(0.4) echo "\t", obj.show() main() # -> Going through one loop iteration # -> Rounded{3} # -> Rounded{3} # -> Rounded{4} # -> Going through one loop iteration # -> Real{3.50} # -> Real{3.90} # -> Real{4.30} 

However, as you can read in this forum , depending on what exactly you need interfaces for other approaches may be better. Also, presumably, the future way of concepts , but, as usual, the manual is dry and related unit tests are cryptic , so I could not translate the previous tuple example into concepts.

If you want to go for a concept, you should ask the forum directly, but be careful, as the manual says, the concepts are still under development .

+3
source

Source: https://habr.com/ru/post/1245428/


All Articles