Re: Understanding Nim compiler
I wrote how to debug Nim program and Nim compiler with GDB long time ago. [https://internet-of-tomohiro.netlify.app/nim/gdb.en.html](https://internet-of-tomohiro.netlify.app/nim/gdb.en.html) It might contain outdated content.
Re: Pass compiler options to file compiled with the compile pragma
It is simpler than my code, but there is a problem in your code when you want to link multiple C files. If 2 C files have same name static variables outside of function, it would generate redefinition error. In C++, redefinition error will be also generated when 2 C++ files have same name variables or functions in anonymous namespace. You can avoid such error by creating 1 nim file per 1 C/C++ files, but I don't think that is not good idea when you want to use many C/C++ files. And when you got compile error from C/C++, line number in the error doesn't match line number in C/C++ files. I think you can fix it by emitting #line N before C code. My code might looks like complicated but linkModule template can be placed in other module and be used in elsewhere without copy it. For example: test1.c static int x = 1; int getX1() { return x; } Run test2.c static int x = 2; int getX2() { return x; } Run testc.nim const Ccode1 = staticRead"test1.c" Ccode2 = staticRead"test2.c" {.emit: Ccode1.} {.emit: Ccode2.} Run sample.nim import testc proc getX1(): cint {.importc.} proc getX2(): cint {.importc.} echo getX1(), getX2() Run
Pass compiler options to file compiled with the compile pragma
There is still no way to pass C/C++ compiler flags to only c/c++ files added by compile pragma. Related RFC: [https://github.com/nim-lang/RFCs/issues/137](https://github.com/nim-lang/RFCs/issues/137) I found workaround that create static link library from the nim file that only has passC and compile pragma so that passC affect to only c/c++ files specified in that nim file. Because of this bug, this code works only in devel Nim. [https://github.com/nim-lang/Nim/issues/12745](https://github.com/nim-lang/Nim/issues/12745) For example: test.h int getX(); Run test.c int getX() { return MY_X; } Run testc.nim # Pass C compiler options only to test.c {.passC: "-D MY_X=123".} {.compile: "test.c".} Run testmod.nim import os, strformat, std/compilesettings proc getX*(): int {.header: "test.h".} template linkModule(modulePath, nimCmd = "c", nimOptions: static[string] = "") = static: doAssert nimCmd == "c" or nimCmd == "cpp" block: const modName = splitPath(modulePath).tail libpath {.inject.} = querySetting(SingleValueSetting.nimcacheDir) / modName & ".staticlib" modulePath2 {.inject.} = modulePath.quoteShell nimCmd2 {.inject.} = nimCmd nimOptions2 {.inject.} = nimOptions.string {.passL: libpath.} # `--os:any --gc:arc -d:useMalloc` is used to avoid compiling and linking stdlib_io.nim for faster build. # It doesn't affect this module. const cmd = fmt"{getCurrentCompilerExe()} {nimCmd2} --app:staticlib --os:any --gc:arc -d:useMalloc --out:{libpath.quoteShell} {nimOptions2} {modulePath2}" static: echo cmd const ret = gorgeEx(cmd) static: echo ret.output when ret.exitCode != 0: {.error: "Abort due to compile error".} linkModule "testc.nim" Run sample.nim import testmod echo getX() Run
Re: Faster and Safer Raytracing in Nim
How about to use counter based random number generater like philox? [https://www.thesalmons.org/john/random123](https://www.thesalmons.org/john/random123)/ It works like a hash function. When you generate a random number, you make a unique number and pass it the function. You can create unique numbers using pixel coordinate, item index, loop counter, line number, etc. Pros: * deterministic as long as input numbers are deterministic. * Stateless. You can use existing variables to generate random numbers and it can reduce memory usage per thread. * Each random number generations can be executed in parallel as it doesn't need PRNG state update. Increase instruction-level parallelism. Cons: * It require more instructions to generate random number from non-random numbers. > I have found a parallel RNG scheme that allows reproducible multithreaded > result for those who wants to do parallel reproducible Monte-Carlo > simulations: Each RNGs generate different RNG streams but I think 2 RNG streams can be overlapped. All RNGs are seeded with unique random number in your code, but the state of one RNG right after being seeded can be same to the state of other RNG after several status update. (In that case, former RNG generate random number stream that is same to the one from later RNG after several state update) Probability of that happening can be very small, but it looks like [Birthday_problem](https://en.wikipedia.org/wiki/Birthday_problem). You need to use PRNG that have much longer period than number of random numbers actually used to avoid random number stream overlap.
Making 4k intro with Nim
I have made 4k intro samples using Nim programming language. [https://github.com/demotomohiro/nim-4k-intro-sample](https://github.com/demotomohiro/nim-4k-intro-sample) I have wrote a blog post about how to make 4k intro with Nim. English: [https://internet-of-tomohiro.netlify.app/nim/nim4k.en.html](https://internet-of-tomohiro.netlify.app/nim/nim4k.en.html) 日本語: [https://internet-of-tomohiro.netlify.app/nim/nim4k.ja.html](https://internet-of-tomohiro.netlify.app/nim/nim4k.ja.html)
Re: Why nim is slower than other languages(except python) in my test?
clang can run calculation in following code at compile time and generate a code that only print a number. [https://godbolt.org/z/CoNKav](https://godbolt.org/z/CoNKav) You need to take some number at runtime and use it in your calculation if you want to run your calculation at runtime. [https://godbolt.org/z/GcAY6-](https://forum.nim-lang.org/postActivity.xml#https-godbolt-org-z-gcay6)
Re: Why nim is slower than other languages(except python) in my test?
[https://github.com/Kiakra/test-benchmark/blob/master/test](https://github.com/Kiakra/test-benchmark/blob/master/test) 2/main.c [https://github.com/Kiakra/test-benchmark/blob/master/test](https://github.com/Kiakra/test-benchmark/blob/master/test) 2/main.nim Output from your program is same to the program that quit with do nothing. Modern C/C++ compiler remove any code that doesn't affect outputs. If you want to benchmark how compiler's optimizer optimize your code, output result of calculation to stdout or somewhere.
Re: Weird Behaviour
According to Nim manual: [https://nim-lang.org/docs/manual.html#syntax-precedence](https://nim-lang.org/docs/manual.html#syntax-precedence) > Whether an operator is used a prefix operator is also affected by preceding > whitespace (this parsing change was introduced with version 0.13.0): > > echo $foo > > # is parsed as > > echo($foo) See how Nim parse your code: import macros dumpTree: var x = number.len-2 var y = number.len - 2 var z = number.len- 2 var a = number.len -2 Run Output: StmtList VarSection IdentDefs Ident "x" Empty Infix Ident "-" DotExpr Ident "number" Ident "len" IntLit 2 VarSection IdentDefs Ident "y" Empty Infix Ident "-" DotExpr Ident "number" Ident "len" IntLit 2 VarSection IdentDefs Ident "z" Empty Infix Ident "-" DotExpr Ident "number" Ident "len" IntLit 2 VarSection IdentDefs Ident "a" Empty Command DotExpr Ident "number" Ident "len" Prefix Ident "-" IntLit 2 Run
Re: Nim's float issue?
You can learn how float works in following web sites: [https://float.exposed](https://float.exposed)/ [https://en.wikipedia.org/wiki/IEEE_754](https://en.wikipedia.org/wiki/IEEE_754)
Re: Hot code reloading
I wrote a sample Hot code reloading with GLFW. I placed it on gist because I think the source code is too long to put in this forum. [https://gist.github.com/demotomohiro/64050496bb615c50fa608d7105509a53](https://gist.github.com/demotomohiro/64050496bb615c50fa608d7105509a53) It seems there are bugs related to hot code reloading. * compile: "foo.c" pragma cause link time error when \--hotcodereloading:on option is used So I used -d:glfwDLL option to avoid that pragma and use glfw3.dll. * [Official opengl module](https://github.com/nim-lang/opengl) doesn't work when \--hotcodereloading:on option is used. Program crash when loadExtensions() is called. This module use undocumented 'dynlib' feature and I think that doesn't work with hotcodereloading. So I used nimgl/opengl in the sample code. It doesn't use that feature and load OpenGL functions only using documented feature. (But it loads all available OpenGL functions even if it is not used in the program.)
Re: Hot code reloading
I tested this with Nim v1.0.6 on Windows 8.1. Build nimhcr.dll and nimrtl.dll: cd c:\my\path\to\nim nim c -d:release lib/nimrtl.nim nim c -d:release lib/nimhcr.nim Run Put them in the parent directory of mymain.nim or an directory PATH env var contain. As sample code in the [instructions](https://nim-lang.github.io/Nim/hcr) failed to compile, I tested following code. #logic.nim #*** import the hotcodereloading stdlib module *** import hotcodereloading import os, times var lastMod = getLastModificationTime(currentSourcePath()) proc update*() = echo "bar" let t = getLastModificationTime(currentSourcePath()) if t > lastMod: if execShellCmd("nim c --hotcodereloading:on mymain.nim") == 0: lastMod = t #*** reload this logic.nim module on this file updated.*** performCodeReload() sleep 1000 Run #mymain.nim import logic proc main() = while true: update() main() Run Build mymain.nim and run mymain.exe: nim c --hotcodereloading:on mymain.nim mymain.exe Run Change code in logic.nim from echo "bar" Run to echo "foo" Run When I save it to the file, it is rebuilt and reloaded automatically.
Re: Unicode support for Windows 10 console
> On Windows console applications the code-page is set at program startup to > UTF-8. Use the new switch -d:nimDontSetUtf8CodePage to disable this feature. > [https://github.com/nim-lang/Nim/blob/devel/changelogs/changelog_1_0_0.md](https://github.com/nim-lang/Nim/blob/devel/changelogs/changelog_1_0_0.md)
Re: Wrapped C++ code is leaking memory
Destructor in C++ is a function that called automatically and usually you don't need to call it explicitly. If an object is a local variable, destructor is called when returning from the function. If an object is allocated with new operator, destructor is called when you use delete operator to it. In [https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/SmilesParse/SmilesParse.h](https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/SmilesParse/SmilesParse.h) RDKIT_SMILESPARSE_EXPORT RWMol *SmilesToMol(const std::string , const SmilesParserParams ); Run In [https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/RWMol.h](https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/RWMol.h) class RDKIT_GRAPHMOL_EXPORT RWMol : public ROMol { Run In [https://github.com/apahl/rdkit_nim/blob/master/src/rdkit/mol.nim](https://github.com/apahl/rdkit_nim/blob/master/src/rdkit/mol.nim) type ## The base Mol object Mol* = ref object obj*: ptr ROMol Run Mol.obj take pointer to ROMol returned from SmilesToMol. I guess SmilesToMol allocate RWMol with new operator and it is supposed to be freed with delete operator. But delete operator is not used in your example code. [https://github.com/apahl/rdkit_nim/blob/master/examples/ex03_mem.nim](https://github.com/apahl/rdkit_nim/blob/master/examples/ex03_mem.nim) Calling destructor of RWMol cleanup resources it has but it doen't free the heap memory of RWMol. [https://github.com/rdkit/rdkit/blob/f8a4020789b3d106a257762b7f70b5cfe992f27c/Code/GraphMol/SmilesParse/SmilesParse.h#L116](https://github.com/rdkit/rdkit/blob/f8a4020789b3d106a257762b7f70b5cfe992f27c/Code/GraphMol/SmilesParse/SmilesParse.h#L116) inline std::unique_ptr operator"" _smiles(const char *text, size_t len) { Run This operator call SmilesToMol and return RWMol wrapped with std::unique_ptr. So you don't need to use delete operator or anything to free pointer to RWMol but it automatically freed. But I don't know nim can work with operator"" or std::unique_ptr. [https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/Substruct/SubstructMatch.cpp#L286](https://github.com/rdkit/rdkit/blob/master/Code/GraphMol/Substruct/SubstructMatch.cpp#L286) std::vector SubstructMatch( const ROMol , const ROMol , const SubstructMatchParameters ) { Run SubstructMatch returns std::vector and it is automatically freed when exiting createLotsOfMolecules proc. You don't need to call destructor of std::vector.
Re: OK, a collection of complains
> -w is used when invoking C compiler > How could I believe a compiler that > can't generat clean C code? There are test code that check correctness of Nim. [https://github.com/nim-lang/Nim/tree/devel/tests](https://github.com/nim-lang/Nim/tree/devel/tests) Warnings in C compiler are for preventing C programmer making mistake. I don't think how people make mistake when writing C by hand and generating it from a programm is same. Clean C code would be important when you work with C programmers who read or edit your code. But Nim genereated C code is not supposed to be read or edit by human. Correctness and efficiency are more important than generating a C code easy to read for humans in Nim. > NIM_CONST is nothing for C++ const in C++ doesn't help optimizer. [https://stackoverflow.com/questions/212237/constants-and-compiler-optimization-in-c](https://stackoverflow.com/questions/212237/constants-and-compiler-optimization-in-c) [https://stackoverflow.com/questions/3896050/does-const-help-the-optimizer-c](https://stackoverflow.com/questions/3896050/does-const-help-the-optimizer-c) const in C++ is for preventing programmer making mistake. I don't think it is important for Nim generated C++ code. > Oh, the last and the least one, those It templates do not look fancy to me > now. > school.students.filterIt(it.grade == 3) > I will never use it to > represent a student in this example. I think it in filterIt template stands for _iterator_ , not pronoun _it_. It is possible to make a filterIt template that take an identifier that is used insted of it. template filterIt(s, name, pred: untyped): untyped = var result = newSeq[type(s[0])]() for name {.inject.} in items(s): if pred: result.add(name) result let temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] acceptable = temperatures.filterIt(this, this < 50 and this > -10) notAcceptable = temperatures.filterIt(that, that > 50 or that < -10) doAssert acceptable == @[-2.0, 24.5, 44.31] doAssert notAcceptable == @[-272.15, 99.9, -113.44] Run
Re: A path commonPrefix function
When your commonPrefix takes 2 paths, length of both paths are n and both paths has no common prefix, it has O(n^2) time complexity. Because startsWith proc is O(n) and it is called n times. relativePath proc in os module calculate common prefix in O(n) time complexity. [https://github.com/nim-lang/Nim/blob/devel/lib/pure/os.nim](https://github.com/nim-lang/Nim/blob/devel/lib/pure/os.nim)
Re: Nim compiling using MS VS2015 (windows)
If you want Nim to C/C++ compiler in MS visualstudio, just call nim with \--cc:vcc option. If you want to see how Nim call cl.exe, add \--listcmd option. For example: nim c --cc:vcc --listcmd test.nim Run If you want Nim always use cl.exe, add cc = vcc in nim.cfg. And put the cfg file in %APPDATA%/nim/nim.cfg. If you want to use cl.exe in specific nim file, put the nim.cfg in the same directory. (Detail of how Nim process configuration files: [https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files](https://nim-lang.org/docs/nimc.html#compiler-usage-configuration-files)) I don't think it is a good idea to edit C:nimconfignim.cfg or nim.cfg in Nim install directory. When you update your Nim, that file is also replaced by new one. @AmbrusFernas I don't understand what you are trying, but if you just want to use Nim on windows, you can install Nim using choosenim. [https://github.com/dom96/choosenim](https://github.com/dom96/choosenim) It also install mingw32 as backend C compiler.
Re: Pragmas Above Procs
Putting pragma above proc only makes sense when a pragma is important more than proc name or parameters but I think it is rare case. When I use a proc, proc name, parameters or return type is more important than importC, noSideEffect, raises, etc. There are many procs with pragma os module source code. [https://github.com/nim-lang/Nim/blob/devel/lib/pure/os.nim](https://github.com/nim-lang/Nim/blob/devel/lib/pure/os.nim) But in the document of os module, pragmas are omitted. [https://nim-lang.org/docs/os.html](https://nim-lang.org/docs/os.html) If you still think pragma should be above proc, I think it is possible to create a macro that adds pragma to a proc below. threadProc: proc worker() = ... withPragma(thread): proc worker() = ... Run I mainly used C++ language before I found Nim language. When I start writing Nim code, type name comes after variable/proc name syntax confused me. But I got used it now.
Re: why md5.toMD5 violate {. noSideEffect .} pragma? and why modify var T not violate it?
> why nse5 not fail to compile? it's modify input --> s before call = "hello" > while s after call = "hellohi" It is explained here: [https://nim-lang.org/docs/manual.html#pragmas-nosideeffect-pragma](https://nim-lang.org/docs/manual.html#pragmas-nosideeffect-pragma) > why nse6 fail to compile? it's just call md5.toMD5 and not modify anything Low level memory operations like copyMem, or zeroMem are used inside toMD5 proc. I think that is why Nim say "'nse6' can have side effects". [https://github.com/nim-lang/Nim/blob/version-1-0/lib/pure/md5.nim#L180](https://github.com/nim-lang/Nim/blob/version-1-0/lib/pure/md5.nim#L180)
Re: Can proc/method name be used as parameter
You can pass a procedure without making anonymous Procs if procedure type match. type TestType = object proc testCallback(callback: proc(this: TestType) {.closure, gcsafe, locks: 0.}, this: TestType) = this.callback() proc helloNim(this: TestType) = echo "Hello, Nim!" proc testProc(this: TestType) = testCallback(helloNim, this) var t: TestType t.testProc() Run or proc testCallback(callback: proc() {.closure, gcsafe, locks: 0.}) = callback() proc helloNim() = echo "Hello, Nim!" testCallback(helloNim) Run
Re: Compilation error after upgrade to 1.0.2 from 0.19
According to your error message, it seems tokens[ITEM_NAME] is Option[system.string] type and you are trying to add it to seq[string] type result variable. You might need to read this document and learn how to get a value from an Option type. [https://nim-lang.org/docs/options.html](https://nim-lang.org/docs/options.html)
Re: Using different compilers on windows
You can change C/C++ backend compiler with --cc option. [https://nim-lang.org/docs/nimc.html#compiler-selection](https://nim-lang.org/docs/nimc.html#compiler-selection) For example, \--cc:vcc use cl.exe in MS Visual Studio. \--cc:clang use clang. If you want to use different gcc, add following option to your cfg file. gcc.exe = "c:\\path\\to\\your\\gcc.exe" Run
Re: Nim for Statistics
I don't know much about Statistics, but this project might help you. Nim4Colab is a IPython extension to use Nim language on Google Colaboratory. Github repo: [https://github.com/demotomohiro/nim4colab](https://github.com/demotomohiro/nim4colab) Related Nim forum thread: [https://forum.nim-lang.org/t/4944](https://forum.nim-lang.org/t/4944)
Re: How to separate a numerator line and a denominator line?
Thank you! This code worked. proc foo: float = ( 1.0 )/ #- (1.0 + 2.0 + 3.0) echo foo() Run
How to separate a numerator line and a denominator line?
I found a interesting GLSL code on Twitter: [https://twitter.com/valentin_galea/status/1188147946468134913](https://twitter.com/valentin_galea/status/1188147946468134913) I tried to write a code in similar way in Nim, but no success. proc foo: float = 1.0 / (1.0 + 2.0 + 3.0) proc foo2: float = # compile error (1.0 / (1.0 + 2.0 + 3.0)) Run template ``(x, y: untyped): untyped = x / y proc foo3: float = 1.0 (1.0 + 2.0 + 3.0) proc foo4: float = # compile error ( 1.0 (1.0 + 2.0 + 3.0)) Run Is it impossible to write code like this in Nim?
Re: Possible to use identifier construction to call proc by name (string)?
I don't think nameToProc can be a compileTime variable because an address of procedure cannot be determined at compile time.
Re: Stuck on while compiling
Your problem might related this issue: [https://github.com/nim-lang/Nim/issues/8648](https://github.com/nim-lang/Nim/issues/8648) When backend C compiler output large message to stdout, Nim compiler hangs. It seems Nim compiler hangs with smaller message on Windows than on Linux. This code passes const string in Nim code to C code as define. test.nim: const FOO = "abcd" proc xyz() {.importc.} xyz() {.passC: "-DFOO=\\\"" & FOO & "\\\"".} {.compile: "test.c".} Run test.c: #include void xyz() { printf("%s\n", FOO); } Run
Re: Tables - can't get the address of value
From: [https://nim-lang.org/docs/manual.html#statements-and-expressions-the-addr-operator](https://nim-lang.org/docs/manual.html#statements-and-expressions-the-addr-operator) > The addr operator returns the address of an l-value. From: [https://nim-lang.org/docs/manual.html#procedures-var-return-type](https://nim-lang.org/docs/manual.html#procedures-var-return-type) > A proc, converter or iterator may return a var type which means that the > returned value is an l-value and can be modified by the caller: In other words, when a return type is not a var type, it is not an l-value. From: [https://nim-lang.org/docs/tables.html#%5B%5D%2CTable%5BA%2CB%5D%2CA](https://nim-lang.org/docs/tables.html#%5B%5D%2CTable%5BA%2CB%5D%2CA) [https://nim-lang.org/docs/tables.html#%5B%5D%2CTable%5BA%2CB%5D%2CA_2](https://nim-lang.org/docs/tables.html#%5B%5D%2CTable%5BA%2CB%5D%2CA_2) > proc `[]`[A, B](t: Table[A, B]; key: A): B > > proc `[]`[A, B](t: var Table[A, B]; key: A): var B So in your `CreateBuffers` proc, `proc `[]`[A, B](t: Table[A, B]; key: A): B` is called and it doesn't return var type. You can get an address only from an l-value. That is why you cannt use `unsafeAddr` in your code. You can not access `seq[0]` when the lenght of the sequence is 0. I think your code shoulde be like: proc CreateBuffers*(obj: var RenderableObject) {.inline.} = # # # glBufferData(GL_ARRAY_BUFFER, obj.vertices_tbl[f].len*sizeof(GLfloat), if obj.vertices_tbl[f].len == 0: nil else: obj.vertices_tbl[f][0].unsafeAddr, GL_STATIC_DRAW) Run > if I pass it with var like obj: var RenderableObject it works, but that kinda > defeats the purpose of using tables and its very slow I don't understand neither why you are using tables in your code nor why `var` defeats the purpose of using tables only from your code.
Re: Nim Seq.add vs. C++ Vector.push_back performance
On my bit old Gentoo linux machine, $ nim -v Nim Compiler Version 0.20.2 [Linux: amd64] Compiled at 2019-07-30 Run C++: 3.4269 nim c -r -d:release seqbench.nim 6.683s nim c -r -d:danger seqbench.nim 6.986s nim cpp -r -d:danger seqbench.nim 7.011s nim c -r -d:danger --gc:none seqbench.nim 3.922s nim c -r -d:danger --newruntime seqbench.nim 5.769s Run According to this document, [https://nim-lang.org/docs/gc.html](https://nim-lang.org/docs/gc.html) > The GC is only triggered in a memory allocation operation. It is not > triggered by some timer and does not run in a background thread. Your code allocate heap memory inside the loop. It seems GC is a bottleneck.
Re: Nim VS The World (CoffeeScript/Boo/PureBasic/C#/ES2018/Python)
There are platform without GUI or clipboard. (e.g. embed system, Linux without Xorg) Making std GUI / drawing / clipboard library means that the language doesn't support such platforms? When I want to compile these language that has std GUI / drawing / clipboard library, I also have to build these library (that could be large) even if I want to make a CLI app? > Yes, quite a lot. Std GUI lib means that you can and will be able to make ui > using same code for every compatible platform and 90% extensions (like custom > controls) you will find gonna be compatible with it, not divided amidst > plenora of third-party libraries. > > Std clipboard lib means there gonna be dependency-free clip access from any > supported platform, not just Windows (using my nimble package). Cost of implementing such std GUI / drawing / clipboard is not smaller than third-party one, isn't it? If there is a such third-party library supports major platforms, nice license, open source, why is std one needed?
Re: Integrate a GLSL shader in Nim
Thank you for the nice video! Noise texture in the shader used in your video is not just random texture. This is the code in the shader that samples noise texture: float Noise( in vec3 x ) { vec3 p = floor(x); vec3 f = fract(x); f = f*f*(3.0-2.0*f); vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy; vec2 rg = texture( iChannel0, (uv+ 0.5)/256.0, -99.0 ).yx; return mix( rg.x, rg.y, f.z ); } Run This is code from Dave_Hoskins's comment in [https://www.shadertoy.com/view/4sfGzS](https://www.shadertoy.com/view/4sfGzS) Here is how the noise texture was created: for (int y = 0; y < 256; y++) { for (int x = 0; x < 256; x++) { colour[x, y].r = RandomNumber(); colour[x, y].b = RandomNumber(); } } for (int y = 0; y < 256; y++) { for (int x = 0; x < 256; x++) { int x2 = (x - 37) & 255; int y2 = (y - 17) & 255; colour[x][y].g = colour[x2][y2].r; colour[x][y].a = colour[x2][y2].b; } } Run I think when this shader was created, there is no 3D texture in WebGL1. This `Noise` function make 3D value noise from 1 time 2D texture sampling. rg.y contains a sample of next z layer of rg.x. To make continuous 3D value noise, rg.y need to be a copy of next z layer rg.x value. you can download original Shadertoy textures from here: [https://github.com/beautypi/shadertoy-iOS-v2/blob/master/shadertoy/presets/tex16.png](https://github.com/beautypi/shadertoy-iOS-v2/blob/master/shadertoy/presets/tex16.png) When embeding a shader as string literal in source code, line numbers in error message from GLSL compiler begins from head of that string literal. That makes finding a error line a bit difficult. It seems your program displays GLSL shader error messages inside GLSL code. I wrote following template so that GLSL compiler show error messages with line number in source code and variable name. It prepends `#line` directive to the string literal with line number in source and constant name. template glslSrcImpl(name: untyped; line: int; prefix, src: static string): untyped = const name {.inject.} = block: const pre {.inject.} = prefix l {.inject.} = line + 2 nameStr {.inject.} = astToStr(name) s {.inject.} = src &"{pre}\n#line {l} \"{nameStr}\"\n{s}" template glslSrcHead*(name: untyped; glslVersion: int; src: static string): untyped = const verLine = "#version " & $glslVersion glslSrcImpl(name, instantiationInfo().line, verLine, src) Run Use this template like this: glslSrcHead testFS, 460, """ out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 0.0); } """ Run
Use Nim on Google Colaboratory with Nim4Colab
[Nim4Colab repository](https://github.com/demotomohiro/nim4colab) [My blog post](https://internet-of-tomohiro.netlify.com/google_colab/nim4colab.en.html) You can use [Nim](https://forum.nim-lang.org/postActivity.xml#nim) language on [Google Colaboratory](https://colab.research.google.com/) by using [Nim4Colab](https://github.com/demotomohiro/nim4colab) extension. Copy and paste following code to a cell on [Google Colaboratory](https://colab.research.google.com/) and run. This code download, install and load [Nim4Colab](https://github.com/demotomohiro/nim4colab) extension. !pip install git+https://github.com/demotomohiro/nim4colab.git %load_ext nim4colab Run Then, you can run Nim code by writing your code under `%%nimc`. %%nimc echo NimVersion Run Sample codes: * [Basic](https://colab.research.google.com/drive/1aNmsJmgnxz-4yr1hT0ZdHh9-XQ_8dcRk) * [Make PNG image](https://colab.research.google.com/drive/15w2dtk9QE8QDTsqMeRnWCzR7f2kSseoq) * [Make animation PNG using EGL & OpenGL](https://colab.research.google.com/drive/1J0B0qVvovrJZJI1OU75jIMUjWnymi_6G)
Re: How to set toolchains for cross compilation?
I tested your commands and nim.cfg on my PC (OS:windows8.1, nim-0.19.6). I created following dummy cross compiler: import os echo getAppFilename() echo commandLineParams() Run Then I compiled it and copied to `arm-android-clang.exe` and `arm64-android-clang.exe`. nim.cfg: arm.android.clang.path = r"f:\temp\cross" arm.android.clang.exe = "arm-android-clang.exe" arm.android.clang.linkerexe = "arm-android-clang.exe" arm64.android.clang.path = r"f:\temp\cross" arm64.android.clang.exe = "arm64-android-clang.exe" arm64.android.clang.linkerexe = "arm64-android-clang.exe" Run test.nim: echo "hello" Run I tested following command: nim c --app:lib --os:android --cpu:arm -d:noSignalHandler --hint[CC]:on --listcmd test.nim nim c --app:lib --os:android --cpu:arm64 -d:noSignalHandler --hint[CC]:on --listcmd test.nim Run Output: f:\temp\cross>nim c --app:lib --os:android --cpu:arm -d:noSignalHandler --hint[CC]:on --listcmd test.nim Hint: used config file 'C:\Users\root\scoop\apps\nim\current\config\nim.cfg' [Conf] Hint: used config file 'C:\Users\root\AppData\Roaming\nim\nim.cfg' [Conf] Hint: used config file 'f:\temp\cross\nim.cfg' [Conf] Hint: system [Processing] Hint: test [Processing] f:\temp\cross\arm-android-clang.exe -c -w -fPIC -IC:\Users\root\scoop\apps\nim\current\lib -o f:\temp\nimcache\test\debug\te st.c.o f:\temp\nimcache\test\debug\test.c f:\temp\cross\arm-android-clang.exe -c -w -fPIC -IC:\Users\root\scoop\apps\nim\current\lib -o f:\temp\nimcache\test\debug\st dlib_system.c.o f:\temp\nimcache\test\debug\stdlib_system.c Hint: f:\temp\cross\arm-android-clang.exe -shared -o f:\temp\cross\libtest.so f:\temp\nimcache\test\debug\test.c.o f:\temp\ nimcache\test\debug\stdlib_system.c.o-ldl [Exec] f:\temp\cross\arm-android-clang.exe @["-shared", "-o", "f:\\temp\\cross\\libtest.so", "f:\\temp\\nimcache\\test\\debug\\test.c.o", "f:\\temp\\nimcache\\test\\debu g\\stdlib_system.c.o", "-ldl"] Hint: operation successful (12415 lines compiled; 0.739 sec total; 16.379MiB peakmem; Debug Build) [SuccessX] f:\temp\cross>nim c --app:lib --os:android --cpu:arm64 -d:noSignalHandler --hint[CC]:on --listcmd test.nim Hint: used config file 'C:\Users\root\scoop\apps\nim\current\config\nim.cfg' [Conf] Hint: used config file 'C:\Users\root\AppData\Roaming\nim\nim.cfg' [Conf] Hint: used config file 'f:\temp\cross\nim.cfg' [Conf] Hint: system [Processing] Hint: test [Processing] f:\temp\cross\arm64-android-clang.exe -c -w -fPIC -IC:\Users\root\scoop\apps\nim\current\lib -o f:\temp\nimcache\test\debug\ test.c.o f:\temp\nimcache\test\debug\test.c f:\temp\cross\arm64-android-clang.exe -c -w -fPIC -IC:\Users\root\scoop\apps\nim\current\lib -o f:\temp\nimcache\test\debug\ stdlib_system.c.o f:\temp\nimcache\test\debug\stdlib_system.c Hint: f:\temp\cross\arm64-android-clang.exe -shared -o f:\temp\cross\libtest.so f:\temp\nimcache\test\debug\test.c.o f:\tem p\nimcache\test\debug\stdlib_system.c.o-ldl [Exec] f:\temp\cross\arm64-android-clang.exe @["-shared", "-o", "f:\\temp\\cross\\libtest.so", "f:\\temp\\nimcache\\test\\debug\\test.c.o", "f:\\temp\\nimcache\\test\\debu g\\stdlib_system.c.o", "-ldl"] Hint: operation successful (12415 lines compiled; 0.770 sec total; 16.406MiB peakmem; Debug Build) [SuccessX] f:\temp\cross> Run Paths to cross compiler set on nim.cfg work on my PC. As long as you set `os` or `cpu` different from host's os/cpu and there is no `--compileOnly` options, nim compiler use $cpu.$os.$cc.* variables in .cfg file. `getConfigVar` procedure in [https://github.com/nim-lang/Nim/blob/devel/compiler/extccomp.nim](https://github.com/nim-lang/Nim/blob/devel/compiler/extccomp.nim) is related to this. You also need to set `cc` to $cc so that nim compiler use $cpu.$os.$cc.*. In your case, you set `os:android` and nim/config/nim.cfg has following code: @if android: cc = clang Run So nim picks `arm.android.clang.*` or `arm64.android.clang.*` variables in .cfg without setting `cc = clang` in your nim.cfg file or command line. I think you should check nim is reading your nim.cfg file and all .cfg/.nims files read by nim except your project's nim.cfg and nim/config/nim.cfg are not setting `cpu`, `os`, `cc` or `arm.android.clang.*` options.
Re: How to set toolchains for cross compilation?
If you are using Windows x64 and you add `--os:windows --cpu:amd64` options, Nim still runs as native compile mode. Then, `amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc.exe"` in .cfg file is ignored. If you still want Nim to call `x86_64-w64-mingw32-gcc.exe` rather than `gcc.exe`, add `gcc.exe = "x86_64-w64-mingw32-gcc.exe"` to your .cfg file. `$cpu.$os.$cc.* = "options"` format variables in .cfg file are for cross compile and variables without CPU name and OS name are for native compile. I have only `x86_64-w64-mingw32-gcc.exe` but I tested your test.nim.cfg and nim compile commands. (OS:Windows 8.1 x64, Nim 0.19.6) It called the compiler as specified in `test.nim.cfg`. As I don't have cross compile toolchains, nim said `Error: invocation of external compiler program failed.` execpt when I tried a native compile command. So, your test.nim.cfg file seems working correctly on my machine. Make sure nim compiler reads your `test.nim.cfg`. If so, nim output includes a line like `Hint: used config file 'c:\foo\test.nim.cfg' [Conf]`. Please add `--listcmd` option to nim command to check what commands nim is actually calling to compile C files.
Re: Disparity between Nim and C performance
Variables in Nim outside of procedures are accessible from any procedure in the same module. I think that is why they need to be converted to global variable in C code. [https://godbolt.org](https://godbolt.org)/ show you assembly code that might help you find why some code is slow. Here is C code that is simplified version of your code. It seems compiler optimized `%` operator to `and` instruction. [https://godbolt.org/z/LlCTR_](https://godbolt.org/z/LlCTR_) I moved all local variables to global variable. `%` operator become `idiv` instruction and the values of variables used in the loop are loaded to register before main loop. Compiler might expecting these variable could be changed before calling `main` function. Or compiler doesn't know what `printf` function do and it might think `printf` could change these global variables and call `main` function. [https://godbolt.org/z/91-7gp](https://godbolt.org/z/91-7gp) When I add `static` to these variable, generated asm code seems almost same to local variable version. [https://godbolt.org/z/vCk6yC](https://godbolt.org/z/vCk6yC)
Re: dotNET api bridge, anyone ?
If you write a program that only use windows API, statically link existing library or ship it with DLLs, people can use it without install anything. Are there any reason why you would like to use doNet API rather than windows API or existing Nim or C/C++ libraries? If you want to use Nim with C# or other managed languages, I think you can call Nim procedures from C# by exporting them as C functions using `exportc` pragma and compile it as DLL, then import it to C# code using marshal/DllImport Attribute. [https://docs.microsoft.com/en-us/cpp/dotnet/calling-native-functions-from-managed-code?view=vs-2019](https://docs.microsoft.com/en-us/cpp/dotnet/calling-native-functions-from-managed-code?view=vs-2019) I have never tried it with Nim, but I wrapped C++ code with C functions and called them from C# long time ago.
Re: Immutability -- more ideas
I think there are 2 kinds of immutability: 1. Strong immutability * If a object is referred by a immutable reference, it never change. (According to Rust's the book, "In Rust, the compiler guarantees that when you state that a value won’t change, it really won’t change.") 2. Weak immutability (per symbol immutability) * Modifying a object using a immutable reference is error. * A object referred by immutable reference can be modified by using mutable reference. (Const reference in C++ is this. You can change the value of what const reference refer without using pointer) Immutability in Nim seems compiler forbids changing value using an immutable symbol but it doesn't guarantee the value never change. Following code can be compiled without error. proc foo(imu: string; mut: var string) = echo imu mut[0] = 'a' echo imu var text = "hello" foo(text, text) Run Output: hello aello Run When `ref` is used, multiple `ref` symbols can refer 1 object. `ref` can refer a object indirectly like: var n:Node = initNode() x:Node = n y:Node = initNode() y.le = n Run Perfect strong immutability would be like if a object is referred by at least 1 immutable reference directly or indirectly, modifying it is compiler error. A object can be modified when it is referred only by mutable symbols. proc addData(x: mut Node; y: Node) = x.data.add(y.data) var n:Node = initNode() addData(n, n) #Compile error because x[] is referred by y and y is immutable. var m:Node = initNode() m.le = n addData(n, m) #Compile error because x[] is referred by y.le and y is immutable. m.le = nil addData(n, m) #No compile error. x[] is not referred by any immutable symbols. Run But which symbol refer which object is determined at runtime and perfect strong immutability cannot be achieved at compile time. (It might be possible at runtime if each object have a counter that counts number of immutable references that refering the object. But I don't think it is what Nim user wants.) For example: proc select(a, b: Node): Node = result = if oracle(): a else: b proc addData(x: mut Node; y: Node) = x.data.add(y.data) #Compile error if y == x but not if y != x? var n:Node = initNode() m:Node = initNode() addData(n, select(n,m)) Run So making strong immutability at compile-time could be like conservatively forbid any changing of objects if they can be referred by any immutable reference. Then, `proc addData(x: mut Node; y: Node)` is always compile error. Any procedures that have at least 2 same type parameters and one of them is immutable and other is `mut` result in compile error. People have to use `mut` parameters even if they are supposed to be not modified. proc replace(n, sub, by:mut Node):Node = ## If ``sub`` is subtree of ``n``, replace it with ``by``. ## ``sub`` and ``by`` are supposed to be not modified but compiler don't think so. Run Conservative strong immutability seems like hard to write code or every parameters become `mut`. Strong immutability might be possible without any runtime check/cost by copying rust's ownership, borrowing and references. [https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) > At any given time, you can have either one mutable reference or any number of > immutable references. > > References must always be valid. You cannot have a mutable reference while you have an immutable one. And you cannot have multiple mutable references. So you will get compile-error from this code: proc addData(x: mut Node; y: Node) var n:Node = initNode() addData(n, n) Run Per symbol immutability only forbid modification using immutable symbols. Objects referred by immutable symbols could be changed using mutable symbols. Per symbol deep immutability would be like compiler forbid changing any fields of immutable symbols. It still partially protect people from setting value to wrong variable and procedure signature can tell which parameters supposed to modify a object or not. proc foo(imu: Node; mu: Node) = imu.data = "foo" #Error imu.le.data = "foo" #Error mu.data = "foo"#OK, even if imu == mu mu.le.data = "foo" #OK, even if imu.le == mu #Both harmless and harmful are vaild. proc harmless(a, b: Node) = var x = construct(a, b) x.data = "mutated" proc harmful(a, b: Node) = var x = select(a, b) x.data = "mutated" Run If you want strong immutability, copying rust's rule could be a goot option unless there is better idea. But
Re: Nim nightly builds
Thank you for notifyng me about that. I fixed the script and sent PR to Wandbox.
Re: Nim nightly builds
Following code worked to download latest devel release. I tested it several times and it has been merged to wandbox. curl -s https://api.github.com/repos/nim-lang/nightlies/releases | \ grep -m 1 "\"browser_download_url\": \"https://github.com/nim-lang/nightlies/releases/download/\(.*\W\)\?devel\W.*-linux\.tar\.xz\"" | \ sed -E 's/.*"browser_download_url\": \"([^"]+)\"/\1/' | \ wget -qi - -O nim.tar.xz Run Here is a script to download and build nighly release Nim. [https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/install.sh](https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/install.sh)
Re: vecctor items iterator
I don't know this is the best way to make `iterator mitems*[T](a: var Vector[T]):var T` works, but this code works. It looks like nim just replace calling `proc `[]`*[T](this:var Vector[T]; index: int): var T` to `v[i]`. `std::vector[T]::operator[ ](size_type pos)` returns reference to a element. But a iterator returns `var T` is mapped to pointer to T in C++ code. `(addr a[i])[]` returns `var T` in Nim and become `&(v[i])` in C++ code. {.emit: """ using namespace std; """.} type Vector* {.importcpp: "std::vector", header: "".}[T] = object proc constructVector*[T](size: cuint): Vector[T] {. importcpp: "vector<'*0>(@)", header: "", constructor.} proc constructVector*[T](size: cuint; data:var T): Vector[T] {. importcpp: "vector<'*0>(@)", header: "", constructor.} proc constructVector*[T](vector: Vector[T]): Vector[T] {. importcpp: "vector<'*0>(@)", header: "", constructor.} proc destroyVector*[T](this: var Vector[T]) {.importcpp: "#.~Vector()", header: "".} proc `[]`*[T](this:var Vector[T]; index: int): var T {.importcpp: "#[@]", header: "".} proc size*[T](this: var Vector[T]): var int {.importcpp: "size", header: "".} iterator mitems*[T](a: var Vector[T]):var T = for i in 0..
Re: Nim GDB Youtube Video
I wrote a blog post about debugging Nim code with GDB. [https://internet-of-tomohiro.netlify.com/nim/gdb.en.html](https://internet-of-tomohiro.netlify.com/nim/gdb.en.html)
Re: Nim nightly builds
Thank you! I can download latest devel release with following command: curl -s https://api.github.com/repos/nim-lang/nightlies/releases | grep -m 1 "\"browser_download_url\": \"https://github.com/nim-lang/nightlies/releases/download/devel-.*-linux\.tar\.xz\"; | sed -E 's/.*"browser_download_url\": \"([^"]+)\"/\1/' | wget -qi - -O nim.tar.xz Run I fixed the script that download and build nighly release Nim. [https://github.com/demotomohiro/wandbox-builder/blob/fixnimhead/build/nim-head/install.sh](https://github.com/demotomohiro/wandbox-builder/blob/fixnimhead/build/nim-head/install.sh) I will send PR of this fix to wandbox after testing this for few days. I thought GitHub GraphQL API is better than REST API because I can minimize amount of data receive from GitHub. But GraphQL API require an OAuth token and putting it on public repository is not a good idea.
Re: Nim nightly builds
That PR has been merged and official nightly build is available on wandbox. But when I select a nim HEAD on wandbox, it uses nim-0.19.2 not 0.19.9. Problem is this URL doesn't always return latest devel version (currently, it is ver 0.19.9), but it could return a latest stable version (0.19.2) [https://api.github.com/repos/nim-lang/nightlies/releases/latest](https://api.github.com/repos/nim-lang/nightlies/releases/latest) I'm studying about Github API to get latest devel version.
Re: Nim nightly builds
I sent a PR to wandbox-builder repository. When it is merged, you can use latest official nightly build on wandbox. [https://github.com/melpon/wandbox-builder/pull/30](https://github.com/melpon/wandbox-builder/pull/30)
Re: Nim nightly builds
Thank you! I can get the URL of latest nightly build for linux and download it with this one liner. curl -s [https://api.github.com/repos/nim-lang/nightlies/releases/latest](https://api.github.com/repos/nim-lang/nightlies/releases/latest) | grep ""browser_download_url": ".*-linux.tar.xz"" | sed -E 's/.*"browser_download_url": "([^"]+)"/1/' | wget -qi -
Re: Nim nightly builds
Thx! But parsing json and finding URL I want to use only with bash script looks hard.
Re: Nim nightly builds
Thank you! That sounds the official nightlies is better. Wandbox has simple test that just compile tiny test code and check output. Test code: [https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/resources/test.nim](https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/resources/test.nim) Test script: [https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/test.sh](https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/test.sh) To use nighty built on wandbox, I need to write a bash script to download it. Is there easy way to get a URL of latest nightly built? Each URL of nightly built file contain hash and it seems difficult to find latest one from script.
Re: Nim nightly builds
Nightly build Nim compiler is available in this online compiler: [https://wandbox.org](https://wandbox.org)/ Select nim language and nim HEAD to use nightly build. I wrote a blog post about Wandbox for Nim users. [https://internet-of-tomohiro.netlify.com/nim/wandbox.en.html](https://internet-of-tomohiro.netlify.com/nim/wandbox.en.html) But it is different nightly build from [https://github.com/nim-lang/nightlies/releases](https://github.com/nim-lang/nightlies/releases). Wandbox do git clone and build nim compiler almost everyday using following script. [https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/install.sh](https://github.com/melpon/wandbox-builder/blob/master/build/nim-head/install.sh) Should wandbox use official Nim nightly build instead of running this script? If so, I will fix the script and send Pull request.
Re: Evaluation order
import macros dumpTree: len"a" + 1 ord'a' + 1 ord 'a' + 1 Run output: StmtList Infix Ident "+" CallStrLit Ident "len" RStrLit "a" IntLit 1 Command Ident "ord" Infix Ident "+" CharLit 97 IntLit 1 Command Ident "ord" Infix Ident "+" CharLit 97 IntLit 1 Run `len"a"` is a Generalized raw string literals. `'a'` is a character literal but there is no generalized character literals. [https://nim-lang.github.io/Nim/manual.html#lexical-analysis-generalized-raw-string-literals](https://nim-lang.github.io/Nim/manual.html#lexical-analysis-generalized-raw-string-literals) So `ord'a' + 1` is parsed as Command invocation syntax.
Re: why var can not be declared this way?
According to Nim manual: [https://nim-lang.org/docs/manual.html#statements-and-expressions-if-statement](https://nim-lang.org/docs/manual.html#statements-and-expressions-if-statement) _In if statements new scopes begin immediately after the if /elif/else keywords and ends after the corresponding then block._ For example: if true: let foo = 1 # Error: undeclared identifier: 'foo' echo foo Run You can write shorter code by using if expression and tuple unpacking [https://nim-lang.org/docs/manual.html#statements-and-expressions-if-expression](https://nim-lang.org/docs/manual.html#statements-and-expressions-if-expression) [https://nim-lang.org/docs/manual.html#statements-and-expressions-tuple-unpacking](https://nim-lang.org/docs/manual.html#statements-and-expressions-tuple-unpacking) proc f(size=1) = let (widFrame, hiFrame) = if size == 1: (320, 200) else: (3200, 2000) echo (widFrame, hiFrame) f(1) f(2) Run
How should relative path calculated?
I implemented `relativePath` that Converts input path to a path relative to baseDir. [https://github.com/nim-lang/Nim/pull/8166](https://github.com/nim-lang/Nim/pull/8166) Is my `relativePath` wrong? It should be implemented like one in other language? Is it worth to be in the Nim Standard Library? This `relativePath` has 3 paramters but similar functions in other language have only 2 parameters. And this pull request was created on 1 Jul, but still it is `S: Waiting on review` status. I don't want to solve conflicts everytime `lib/pure/ospaths.nim` or `tests/stdlib/tospaths.nim` was changed. I wrote why & when my implementation require 3 parameters in the comment: proc relativePath*(path, baseDir: string; curDir: string = ""): string {. noSideEffect, rtl, extern: "nos$1".} = ## Convert `path` to a path relative to baseDir. ## ## `path` and `baseDir` must be absolute paths or relative paths from `curDir`. ## When one of `path` and `baseDir` is relative and other one is absolute, `curDir` must be absolute. ## ## On DOS like filesystem, when a drive of `path` is different from `baseDir`, ## this proc just return the `path` as is because no way to calculate the relative path. ## ## Following pseudo code looks like Nim explains requirements of parameters. ## ## .. code-block:: nim ## ## if isAbsolute(path) and isAbsolute(baseDir): ## # `curDir` is ignored ## else not (isAbsolute(path) or isAbsolute(baseDir)): ## # Both `path` and `baseDir` must be relative to a same path. ## # Suppose ".." is only in front of path, not in middle of path. ## let numParDirsInPath = number of ".." in path ## let numParDirsInBaseDir = number of ".." in baseDir ## if numParDirsInBaseDir > numParDirsInPath: ## # `curDir` can be relative or absolute path. ## # Both `path` and `baseDir` must be relative paths from `curDir`. ## # `curDir` must has (numParDirsInBaseDir - numParDirsInPath) directories or raise ValueError. ## else: ## # `curDir` is ignored ## else: ## # `curDir` must be a absolute path. ## # `curDir` is used to convert `path` or `base` to a absolute path. ## ## For example, relativePath("a", "b") returns "../a", but relativePath("a", "..") raise exception. ## Because result of relativePath("a", "..") requires the parent directory name of "a". ## ## This proc never read filesystem. ## `baseDir` is always assumed to be a directory even if that path is actually a file. ## ## You can find more examples in tests/stdlib/tospaths.nim runnableExamples: doAssert relativePath("/home/abc".unixToNativePath, "/home/abc/x".unixToNativePath) == "..".unixToNativePath doAssert relativePath("abc".unixToNativePath, "xyz".unixToNativePath, "".unixToNativePath) == "../abc".unixToNativePath doAssert relativePath(".".unixToNativePath, "..".unixToNativePath, "/abc".unixToNativePath) == "abc".unixToNativePath doAssert relativePath("/home/xyz/d".unixToNativePath, "xyz".unixToNativePath, "/home".unixToNativePath) == "d".unixToNativePath doAssert relativePath("../d".unixToNativePath, "/usr".unixToNativePath, "/home/xyz".unixToNativePath) == "../home/d".unixToNativePath Run I researched relativePath in other langauges: [https://github.com/nim-lang/Nim/pull/8166#issuecomment-430974787](https://github.com/nim-lang/Nim/pull/8166#issuecomment-430974787) When `path` and `baseDir` are absolute paths, my implementation and other implementation works almost same way. When one of `path` xor `baseDir` are absolute paths, relative path is converted to absolute path using 3rd parameter (NOT using `getCurrentDir`) and a result is calculated from these 2 absolute paths. When both `path` and `baseDir` are relative paths, my implementation works differently from other implementation. My implementation doesn't call procedures that has side effect like getCurrentDir() or setCurrentDir(). When converting (path X relative to A) to (path Y relative to B) where X, Y, A and B are relative path, A and B are directories and B is relative to A, 3rd parameter is required if path Y includes parent directory of path X (In other words, path B has more ".." than path X). For example, if path X = ".", A = "a" and B = ".." then path Y = "a". If path X = "x", A = "a/b" and B = "../.." then path Y = "a/b/x". `relative` function in Boost filesystem takes 2 parameters and they are converted to absolute paths inside the function if they are relative path. [https://www.boost.org/doc/libs/1_68_0/libs/filesystem/src/operations.cpp](https://www.boost.org/doc/libs/1_68_0/libs/filesystem/src/operations.cpp) Converting a relative path to a absolute path requires getting current working directory that
Re: runnableExample considered harmful / good feature to deprecate before 1.0?
Test code can be larger than 100 lines. For example: [https://github.com/nim-lang/Nim/blob/devel/tests/stdlib/tjsontestsuite.nim](https://github.com/nim-lang/Nim/blob/devel/tests/stdlib/tjsontestsuite.nim) Is it a good idea to put such a large test code under runnableExamples? Or if test code is larger than N (20~50?), put them in other file (e.g. "tests/tfoo.nim")? I thought runnableExamples are example codes that help people learning how the proc works. These code are tested so that you don't write a example code that fail to compile or cause assert error.
Re: Some questions about Nim compiler parameters
The usage of the Nim compiler is described in this document: [https://nim-lang.github.io/Nim/nimc.html](https://nim-lang.github.io/Nim/nimc.html) Switches without dash is a command. They specify what Nim compiler do. Switches with one dash or two dashes are options. One dash options are short version of two dashes options. They are used by people who don't want to type long option name. Commands are like name of procedure and options are like parameters of procedure in Nim langauege. This pattern (progname command [options] argments ...)is often used by other command line tool like git, systemctl, ip. About 2nd question, I think you should specify parameters using pragma in the code only when your code depends these parameters. Changing command line switch on command line or on nim.cfg is easier than changin them on the code. 3rd question How Configuration files are processed is described here: [https://nim-lang.github.io/Nim/nimc.html#compiler-usage-configuration-files](https://nim-lang.github.io/Nim/nimc.html#compiler-usage-configuration-files) For example, you can set nimcache option on nim.cfg file like: nimcache = "/tmp/nimcache/$projectName/release" Run If you want to see more example of nim.cfg file, google "nim.cfg" or check [https://github.com/nim-lang/Nim/blob/devel/config/nim.cfg](https://github.com/nim-lang/Nim/blob/devel/config/nim.cfg)
Re: A fast float to string conversion library
Nice! Your dtoa passed my quick pseudorandom number test. import ./src/dtoa import math, parseutils, random proc test0(v: float64) = let s = dtoa(v) var v2:float64 doAssert parseBiggestFloat(s, v2) != 0 doAssert v2 == v proc test(v: float64) = test0(v) test0(-v) test0(1.0/v) test0(-1.0/v) proc testrand(v: float64) = test(v) for i in 0..<1000: let r = rand(2.0) - 1.0 test(v*r) randomize() var x:float64 = 1.0 for i in 0..<1023: x *= 2.0 testrand(x) x = 1.0 for i in 0..<1022: x *= 0.5 testrand(x) for i in 0..<100: let e = rand(1022.0*2.0) - 1022 test(pow(2.0, e)) Run
Re: How to check an auto type parameter in a proce
If type of `a` is really `int`, `float` or `string` you can write code like this: proc myProc1(a: int) = echo "int: ", a proc myProc1(a: float) = echo "float: ", a proc myProc1(a: string) = echo "string: ", a proc myProc(a: auto) = myProc1(a) myProc(1) myProc(2.0) myProc("hello") # Passing other than int, float and string result in compile error #myProc((3,4)) Run Or proc myProc(a: int) = echo "int: ", a proc myProc(a: float) = echo "float: ", a proc myProc(a: string) = echo "string: ", a myProc(1) myProc(2.0) myProc("hello") Run But you sad you need to know the type at runtime. That means parameter `a` is actually pointer or Any in typeinfo module?