Templates and imports
Hello folks, Does anyone know why templates don't "auto-import" symbols defined in their residence file? :( Minimal example: # test.nim import strutils template test_template*() = echo (1.0/3.0).formatFloat(precision=3) proc test_proc*() = echo (1.0/3.0).formatFloat(precision=3) Run # other.nim import test test_proc() # ok test_template() # fail: # /tmp/other.nim(4, 14) template/generic instantiation of `test_template` from here # /tmp/test.nim(5, 17) Error: attempting to call undeclared routine: 'formatFloat' Run Is it a new feature or a bug? I think it worked in a different way some time ago. Nim Compiler Version 1.1.1 [Linux: amd64] Compiled at 2020-02-25 git hash: db540a0223480134598fb4806c55510cdef36bf1 Run
Re: Nim Community Survey 2019
Me too. Is opening an issue a contribution? Is writing a library a contribution? Also I liked to read raw responses as you posted in 2017 survey: [https://nim-lang.org/blog/2017/10/01/community-survey-results-2017.html](https://nim-lang.org/blog/2017/10/01/community-survey-results-2017.html)
Re: Raylib Forever (4Nim)
Suggestion: now create a virus which will spread around the world and install everywhere a fully automated service to convert and deliver latest possible raylib headers, why not? Why your 4 previous wrapping attempts failed?
Re: Nimph is a Nim package handler for the rest of us
Omg, my bad, i was searching for specific installation instructions before i wrote the comment, but i didn't see that section on Github -_- Maybe cause i expected "installation" to be before "usage". Anyway, I'm sorry but calling bootstrap script is not something i expect from nimble package :(
Re: Nimph is a Nim package handler for the rest of us
Well, after not finding it on nimble packages list... nimble install nimph Prompt: nimph not found in any local packages.json, check internet for updated packages? [y/N] Answer: y Downloading Official package list Success Package list downloaded. Tip: 3 messages have been suppressed, use --verbose to show them. Error: Package not found. Run ...and after downloading all the dependencies... Downloading https://github.com/disruptek/nimph using git Verifying dependencies for nimph@0.6.14 Info: Dependency on github@>= 1.0.2 already satisfied Verifying dependencies for github@1.0.2 Info: Dependency on npeg@>= 0.20.0 already satisfied Verifying dependencies for npeg@0.22.2 Info: Dependency on https://github.com/disruptek/rest.git@>= 1.0.0 already satisfied Verifying dependencies for rest@1.0.3 Info: Dependency on foreach@>= 1.0.0 already satisfied Verifying dependencies for foreach@1.0.2 Info: Dependency on cligen@>= 0.9.41 already satisfied Verifying dependencies for cligen@0.9.41 Info: Dependency on bump@>= 1.8.18 already satisfied Verifying dependencies for bump@1.8.19 Info: Dependency on cligen@>= 0.9.40 already satisfied Verifying dependencies for cligen@0.9.41 Info: Dependency on https://github.com/disruptek/cutelog@>= 1.1.2 already satisfied Verifying dependencies for cutelog@1.1.2 Info: Dependency on npeg@>= 0.21.3 already satisfied Verifying dependencies for npeg@0.22.2 Info: Dependency on result@any version already satisfied Verifying dependencies for result@0.1.0 Info: Dependency on https://github.com/disruptek/cutelog@>= 1.1.0 already satisfied Verifying dependencies for cutelog@1.1.2 Info: Dependency on https://github.com/disruptek/gittyup@>= 2.1.0 already satisfied Verifying dependencies for gittyup@2.1.9 Info: Dependency on nimgit2@0.1.1 already satisfied Verifying dependencies for nimgit2@0.1.1 Info: Dependency on nimterop@>= 0.3.3 already satisfied Verifying dependencies for nimterop@0.3.3 Info: Dependency on regex@>= 0.10.0 already satisfied Verifying dependencies for regex@0.13.0 Info: Dependency on unicodedb@>= 0.7.2 already satisfied Verifying dependencies for unicodedb@0.7.2 Info: Dependency on unicodeplus@>= 0.5.0 already satisfied Verifying dependencies for unicodeplus@0.5.1 Info: Dependency on unicodedb@>= 0.7 already satisfied Verifying dependencies for unicodedb@0.7.2 Info: Dependency on cligen@>= 0.9.17 already satisfied Verifying dependencies for cligen@0.9.41 Info: Dependency on https://github.com/disruptek/results@1.0.0 already satisfied Verifying dependencies for results@1.0.0 Info: Dependency on https://github.com/stefantalpalaru/nim-unittest2@>= 0.0.1 already satisfied Verifying dependencies for unittest2@0.0.1 Info: Dependency on regex@>= 0.11.0 already satisfied Verifying dependencies for regex@0.13.0 Info: Dependency on unicodedb@>= 0.7.2 already satisfied Verifying dependencies for unicodedb@0.7.2 Info: Dependency on unicodeplus@>= 0.5.0 already satisfied Verifying dependencies for unicodeplus@0.5.1 Info: Dependency on unicodedb@>= 0.7 already satisfied Verifying dependencies for unicodedb@0.7.2 Installing nimph@0.6.14 Run ... i get this /tmp/nimble_2825/githubcom_disrupteknimph_#head/src/nimph/config.nim(11, 16) Error: cannot open file: compiler/idents Run And yes, I have compiler==1.1.1
Re: grim - graph structures in Nim
Thanks Erik for this lib. I'm curious why you store node attributes in heterogenous table. In compiled language i expect graph to be a generic with custom Node and Edge types known at compile time, smth like var g = newGraph[MyNodeType, MyEdgeType]() Run
Re: Is there a 2D game framework recently updated for Nim ?
[Cat 400](https://github.com/c0ntribut0r/cat-400) is in active development, but it's unstable yet and docs are outdated
Re: binarySearch (from algorithm) not always working
Well then there should be an assert inside binarySearch which should check that. It will be deleted in release build anyway
Re: Why inherit RootObj?
Disagreed. I use inheritance, methods and dynamic dispatch without RootObj.
Re: string to ptr uint8
I guess you may replace input: ptr uint8 with input: cstring, isn't it the same? And then just pass nim string as usual.
Re: fileExists and existsFile. This made my day
Haha @dom96, v1.0 is out...
Re: Pragmas Above Procs
Could be something like this, as ugly as original pragmas :> foo(callback = [closure, gcsafe] proc() = echo "baa") Run
Re: "out of memory" when creating new Thread inside sharedTable lock
Workaround with pointer to table and custom lock ¯_(ツ)_/¯ import tables import strformat import os import typetraits import locks type ThreadName = string ThreadInfo = object thread: Thread[ThreadName] var threads = initTable[ThreadName, ThreadInfo]() let threadsPtr = threads.addr var threadsLock: Lock threadsLock.initLock() proc threadEntrypoint(name: ThreadName) {.thread.} = while true: echo &"Inside thread: name={name}" proc spawn(name: ThreadName) = echo &"Spawning: name={name}" withLock threadsLock: if name in threadsPtr[]: raise newException(ValueError, "Thread with this name was already registered") threadsPtr[][name] = ThreadInfo() threadsPtr[][name].thread.createThread(param=name, tp=threadEntrypoint) echo &"Created thread: name={name}" when isMainModule: spawn(name="a") spawn(name="b") sleep(1000) Run
Re: "out of memory" when creating new Thread inside sharedTable lock
Thanks for testing it! I tried different combinations for writing thread instance to sharedTable. Seems that creating temporary variable may help, but other cases simply don't work: import sharedtables import strformat import os import typetraits type ThreadInfo = object thread: Thread[void] var threads: SharedTable[string, ThreadInfo] threads.init() proc threadEntrypoint() {.thread.} = while true: echo "OK" when isMainModule: let key = "key" # 1) works (well, if it didn't work nim would worth nothing) var value = ThreadInfo() value.thread.createThread(tp=threadEntrypoint) # 2) illegal storage access threads.withKey(key) do (key: string, value: var ThreadInfo, pairExists: var bool): if pairExists: raise newException(ValueError, "Thread with this name was already registered") value = ThreadInfo() value.thread.createThread(tp=threadEntrypoint) pairExists = true # 3) works threads.withValue(key, value) do: echo "Value already exists" do: var info = ThreadInfo() info.thread.createThread(tp=threadEntrypoint) threads[key] = info # 4) hangs forever threads.withValue(key, _) do: echo "Value already exists" do: threads[key] = ThreadInfo() threads.mget(key).thread.createThread(tp=threadEntrypoint) sleep(1000) Run
"out of memory" when creating new Thread inside sharedTable lock
Hello guys! I need your help, cannot figure out wtf is going on here. I made a minimal example which produces an "out of memory" error. The idea is simple: create a "spawn" proc which 1. accepts a name (just a string) 2. runs some dumb thread 3. adds mapping to shared table: name -> thread Since I use shared table, each thread can (safely, due to lock) access other thread information using thread's name. Here is the code: import sharedtables import strformat import os import typetraits type ThreadName = string ThreadInfo = object thread: Thread[ThreadName] # ... and some other info (channel etc) var threads: SharedTable[ThreadName, ThreadInfo] threads.init() proc threadEntrypoint(name: ThreadName) {.thread.} = echo &"Inside thread: name={name}" proc spawn(name: ThreadName) = echo &"Spawning: name={name}" threads.withKey(name) do (key: ThreadName, value: var ThreadInfo, pairExists: var bool): if pairExists: raise newException(ValueError, "Thread with this name was already registered") echo &"withKey: name={key}" value = ThreadInfo() echo &"Creating thread: name={key}" value.thread.createThread(param=key, tp=threadEntrypoint) echo &"Created thread: name={key}" pairExists = true when isMainModule: spawn(name="a") sleep(1000) Run The output is really surprising, I cant google something similar and it's even not an exception: Spawning: name=a withKey: name=a Creating thread: name=a Created thread: name=a out of memory Run It's probably something related to shared table lock and spawning a thread during this lock (but im not sure). I tried different ways to fill that shared table with spawned threads but didn't succeed.
Re: Advantages of "from... X... import Y" over "import Y"?
This is an excellent article imho [https://narimiran.github.io//2019/07/01/nim-import.html](https://narimiran.github.io//2019/07/01/nim-import.html)
Re: Nim based Github Actions
Very handy, thanks a lot!
Re: code to unpack (msgpack) and "cast" object to
There you go [https://github.com/c0ntribut0r/cat-400/blob/master/c4/messages.nim](https://github.com/c0ntribut0r/cat-400/blob/master/c4/messages.nim)
Logging milliseconds
Hello everyone, How do I make logging output milliseconds? Default formatting options are rather conservative in terms of date/time: Format strings support the following variables which must be prefixed with the dollar operator (``$``): $date Current date $time Current time $datetime $dateT$time Run I can't even define my logging subclass cause [substituteLog](https://github.com/nim-lang/Nim/blob/master/lib/pure/logging.nim#L103) is a proc, not method >:( proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string = # ... case v of "date": result.add(getDateStr()) of "time": result.add(getClockStr()) of "datetime": result.add(getDateStr() & "T" & getClockStr()) Run I guess I have to redefine log method but it's a bit ugly solution. Any chance to make logging more configurable?
Re: Nimble cannot find latest version of package
Thanks! It's all clear now.
Re: How to force destroy a ref?
Thank you! You described my problem in more general and more meaningful way! I'm not familiar with C# but I liked the Disposable idea. Now I'll follow your advice and will separate "physical" (=destroy()) and "logical" (dispose()) destruction of object. I love nim community :)
How to force destroy a ref?
Is there any way to destroy a `ref` manually? My object has proc `destroy=`(self: Figure) = gui.eraseFigure(self.handler) Run So when object is garbage collected, it is erased on screen as well. However, object is not collected immediately, so I still see it on screen after removing all references to it. Only when GC comes to the object and destroys it, the object disappears, but it may take significant amount of time. Is there any possibility to say "hey, GC, take a look at this object - it has no references anymore, please collect it asap"?
Re: How to get the address of string ""
If you're using FFI and the proc accepts cstring type, you don't even need to convert string to cstring at all: proc printf(formatstr: cstring) {.importc: "printf", varargs, header: "".} printf("This works %s", "as expected")
Re: How to get the address of string ""
I'm not sure, but here b should contain ptr to empty string - am I right? var a = "" let b = a.cstring echo $cast[int](b) But why do you need this?
importc and dynamic name resolution
Some library's C API functions look like this: h3dAddResource h3dDelResource ... In my nim wrapper I use: {.push dynlib:lib, importc:"h3d$1".} proc AddResource(...) proc DelResource(...) {.pop.} This appends "h3d" before proc name for C API. How can I also make proc names start with lower letters in bulk? Maybe there's a way to pass a translation proc? This would be perfect: {.push dynlib:lib, importc:proc(nimName: string): string = "h3d" & nimName[0].toUpperAscii() & nimName[1..^nimName.len]} proc addResource(...) proc delResource(...)
Re: Why macros can't find a local module?
Heres a [macro for importing by string](https://forum.nim-lang.org/t/3547/1#22257), try it out
Re: proc(t: typedesc): var t -- expected 'None' error
Thank you guys! I stayed with templates, don't know why I didn't use them from the beginning. But typedesc[T] is really, really evil and black magic: proc getMutableVal[T](key: int, desc: typedesc[T]): var T = getTableOf(T)[key]
proc(t: typedesc): var t -- expected 'None' error
I'm trying to simplify my program syntax by creating nice aliases. Cannot understand what's wrong when returning var t where t is typedesc: import tables proc getTableOf*(t: typedesc): ref Table[int, t] = var table {.global.} = newTable[int, t]() return table proc getVal(key: int, t: typedesc): t = # just an easy accessor (alias) getTableOf(t)[key] # check they are the same getTableOf(bool)[0] = false assert 0.getVal(bool) == getTableOf(bool)[0] # for key "0", lookup value in boolean table - this works echo "ok" proc getMutableVal(key: int, t: typedesc): var t = getTableOf(t)[key] getTableOf(bool)[0] = false # get boolean table, select mutable value by key - this works! 0.getMutableVal(bool) = false # same: for key "0", get mutable value from boolean table # ^-- Error: type mismatch: got but expected 'None' assert 0.getVal(bool) == false echo "ok" Please help! :/
Re: How to (de)serialize inherited object?
In case anyone will ever need inheritance support for msgpack: [https://github.com/c0ntribut0r/cat-400/tree/master/c4/wrappers/msgpack](https://github.com/c0ntribut0r/cat-400/tree/master/c4/wrappers/msgpack)
Re: How to (de)serialize inherited object?
Probably there's no easy solution of this task [Same for c++ on Stack Overflow](https://stackoverflow.com/questions/3268801/how-do-you-de-serialize-a-derived-class-from-serialized-data) [Comprehensive guide](https://isocpp.org/wiki/faq/serialization#serialize-inherit-no-ptrs)
Re: How to (de)serialize inherited object?
It would be too easy! import streams, nesm serializable: type TA = object of RootObj TB = object of TA f: int var a: ref TA b: ref TB new(b) a = b echo stringify(serialize(a)) lib/nim/system.nim(2833, 7) Error: unhandled exception: kind(thetype[1]) == nnkEmpty Inheritence not supported in serializable
Re: how to read/write object from/to binary file?
Have a look at this: import streams type MyType* = object somefield*: array[10, int16] var t1, t2: MyType t1.somefield[0] = 1 t2.somefield[0] = 2 var f = newFileStream("/tmp/tmp.mytype", fmWrite) if not f.isNil: f.write t1 f.write t2 f.flush var r1, r2: MyType var f2 = newFileStream("/tmp/tmp.mytype", fmRead) discard f2.readData(r1.addr, r1.sizeof) discard f2.readData(r2.addr, r2.sizeof) echo r1.somefield echo r2.somefield
How to (de)serialize inherited object?
Hello guys, Is there any way to serialize object including its runtime type data? Both [marshal](https://nim-lang.org/docs/marshal.html) and [msgpack4nim](https://github.com/jangko/msgpack4nim#ref-types) don't support it out-of-box. import streams, msgpack4nim type TA = object of RootObj TB = object of TA f: int var a: ref TA b: ref TB new(b) a = b echo stringify(pack(a)) #produces "[ ]" or "{ }" #not "[ 0 ]" or '{ "f" : 0 }' I know about object variants but if I use them I will lose the elegance of dynamic dispatch and will have to write those ugly case obj.kind of kndA: # 50 lines of code of kndB: # another 50 loc # ... etc One possible solution is to write a macro that will pack class name together with the data, like genPackers(TA, TB, TC, ...) # transforms into: method pack*(a: ref TA): string = pack "TA" # specify runtime type as string pack a method pack*(b: ref TB): string = pack "TB" pack b proc unpack*(data: string): ref TA = var typ: string = unpack(data) case typ of "TA": result = unpack[TA](data) of "TB": result = unpack[TB](data) # ... This will probably work, but is there a better solution, without strings of class names and lising all possible classes? Kinda proc pack(anything: ref TA): string = pack(anything.runtimeType) # pack internal type info pack[anything.runtimeType](anything) # pack the object with respect to its runtime type proc unpack(data: string): ref TA = let runtimeType = unpack[typeInfo](data) # unpack runtime type result = unpack[runtimeType](data) # unpack data according to that runtime type
Defining variable in nim.cfg
Hello, I have a long compilation command like this: nim c -r -o=../build -d:myUglyVariable:"myUglyValue" main.nim --loglevel=DEBUG I'd like to move all that in nim.cfg, or at least that ugly variable, so that I type just nim c -r main.nim Is that possible? I really lack any docs on nim.cfg file syntax.
Re: Resources embedding
Not an expert, but afaik string is just a sequence of chars and char is always a byte. Thus you just staticRead and then may access each byte using subscript []. Haven't heard about other ways of dancing with bytes in nim :/
Re: Has anyone else been bitten by this?
At my (newbie's) point of view, you're right - conversion makes n being an expression. This wouldn't be a problem if there was overloading resolution by return type and you wouldn't need to use those x: var int8, but there's no hope [https://forum.nim-lang.org/t/3025](https://forum.nim-lang.org/t/3025)
Re: Get location of nimcache folder at compile time
The only thing I found is that nimscript function What's the use-case btw? I found the rule: when I try to do smth and there's no easy solution for it -> probably my code smells and I'm doing smth totally wrong Why do you ever need to touch the cache?
Re: Import module by name / absolute path
That's why I like nim! Got a reply on my questions in 5 minutes from Araq! Thank you
Re: Get location of nimcache folder at compile time
Maybe system.nimscript.nimcacheDir() may help? [See github](https://github.com/nim-lang/Nim/blob/08950649839c1df1504d495fccfea04bf11f55ed/lib/system/nimscript.nim#L246)
Import by
Consider I have these modules which define the same functions (only implementation differs): -math_precise.nim -math_optimal.nim -math_fast.nim Now I want to include them based on compile-time option. I know I can use const math {.strdefine.}: string = "precise" # default value when math == "precise": # <-- here I hardcode possible values import math_precise elif math == "fast": import math_fast And then nim c -d:math:fast 1) What if I don't want to hardcode modules names and just import by name? Like const math {.strdefine.}: string = "precise" # default value import "math_" & math # <-- Error: invalid module name :( I guess I should play with macros? 2) Also, is there any way to import module by absolute location? import /tmp/math_superfast 3) Will things work if I use "include" instead of "import"? (I know the difference between them)
Re: Dynamic dispatch and star wars
@mashingan Yeah, that's true. However, the proposed idea would be a very comfortable way to override library's methods. But because of UB now user has to pass either subclass with custom methods or pointers to procs to the library which I find a bit messy. Imagine a math library which does some calculations. Inside it there's a method to calculate square root. One day user understands that he knows a better and faster square root implementation. How can he "inject" it there? Currently there's no way unless lib authors allow him (in advance) to use some setting like sqrt = ref proc(x: float): float P.S. I came from Python so static programming languages are big pain for me
Re: Dynamic dispatch and star wars
Thank you! Yeah you got the idea! Compiler doesn't allow to redefine a proc/method in the same module, however **redefinition across modules compiles fine**. I wanted to use this trick to allow users redefine my library methods in their code - just like that kill in main.nim. It is much simpler than using inheritance or other methods to inject user-defined code - just use internal dispatch trees that will do all redefinition job for you Undefined behaviour here is really undefined. What made me curious is that definition order is always the same (kill from main.nim is always defined last), but dispatch depends on other non-related methods which is counter-intuitive... P.S. Thanks for var notice. Actually it is a part of a larger codebase where the reassignment really happens. I just omitted some unnecessary code.
Dynamic dispatch and star wars
Okay guys, this is something that blows my mind away! I've wiped everything redundant from my code and added Star Wars to make it funnier, but the problem is really terrifying me. Consider we have a class Hero and a method for a Hero to kill another Hero: # heroes.nim type Hero* = object of RootObj method kill*(self: var ref Hero, victim: ref Hero) {.base, inline.} = discard # by default no one can kill another Hero. kill() just does nothing Now we create a bit of Jedi: # jedi.nim import heroes type OB1* = object of Hero Yoda* = object of Hero method kill*(self: var ref Hero, victim: ref OB1) = echo("Obi Wan Kenobi was killed") method kill*(self: var ref Hero, victim: ref Yoda) = echo("Yoda was killed") # Even Jedi may be killed! For the sith, let's add a Startrooper. I never liked them so we won't use it anywhere. However, its role is significant! (see below) # sith.nim import heroes type Startrooper* = object of Hero method kill*(self: var ref Hero, victim: ref Startrooper) = echo("Startrooper was killed... one more") Now let's play! # main.nim import heroes import jedi # import sith # <-- leave for now # this method will protect Yoda from being killed by anyone method kill(self: var ref Hero, victim: ref Yoda) = echo("Yoda may not be killed!") var darthVader = new(ref Hero) yoda = new(ref Yoda) # this call matches exactly the newly defined method above darthVader.kill(yoda) # outputs "Yoda may not be killed!", as expected Now we add sith... # main.nim import heroes import jedi import sith # <-- uncomment this # this method will protect Yoda from being killed by anyone method kill(self: var ref Hero, victim: ref Yoda) = echo("Yoda may not be killed!") var darthVader = new(ref Hero) yoda = new(ref Yoda) # this call matches exactly the newly defined method above darthVader.kill(yoda) # outputs "Yoda was killed"... WAT?! Do you see it too? We added a method to kill a Startrooper (method kill(self: var ref Hero, victim: ref Startrooper)) and suddenly our Yoda's protection is broken! What the hell?! Now leave sith module included and let's comment killing Obi Wan Kenobi: # jedi.nim import heroes type OB1* = object of Hero Yoda* = object of Hero # method kill*(self: var ref Hero, victim: ref OB1) = echo("Obi Wan Kenobi was killed") method kill*(self: var ref Hero, victim: ref Yoda) = echo("Yoda was killed") Guess what?! "Yoda may not be killed!" So, when you add sith module with Startrooper killing, Yoda's protection becomes broken, but when you make Kenobi immortal, Yoda's protection is back! Now here's the question: how close to schizophrenia I am?
Re: Understanding staticRead's weird behaviour
Oh, thank you all. Didn't know that readFile requires ffi... Nim looks so easy but the deeper you dive the more complex it is.
Understanding staticRead's weird behaviour
Hello nim lovers! Another portion of dumb questions from nim newbie 1) Consider this project structure: app.nimble app/ - version.txt # contains "0.1.1-3" - utils.nim utils.nim contains getVersion helper which just reads from file: proc getVersion*(versionFile:string): seq[string] = staticRead(versionFile).split('-') # static is required because I need this value at compile time app.nimble: const versionFile = "app/version.txt" # ... task version, "Get version": echo "Proc call: " & $(getVersion(versionFile)) echo "Inline call: " & $(staticRead(versionFile).split('-')) Now here is the magic: > nimble version Executing task version in .../app.nimble Proc call: @[0.1] <-- WTF?! Inline call: @[0.1.1, 3] Okay, it looks like calling staticRead is cached somehow when using a proc (cause I had "0.1" some time ago). But why, and how to avoid it? 2) My versionFile must be defined **relative to `utils.nim` location** because that's where staticRead resides. If I move utils somewhere else, I would need to change versionFile's path which is absolutely terrible! 3) Also, just curious why we have to use staticRead at all? Looks like const already marks expressions as compile-time: const constEval = contains("abc", 'b') # computed at compile time, no need to use staticContains or smth data = readFile("somefile") # <-- OOPS! doesn't work at compile time data = staticRead("somefile") # <-- will work Cannot nim distinguish between compile/runtime and call appropriate read function accordingly?