Re: Understanding Nim compiler

2020-07-13 Thread demotomohiro
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

2020-07-03 Thread demotomohiro
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

2020-07-03 Thread demotomohiro
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

2020-05-28 Thread demotomohiro
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

2020-05-06 Thread demotomohiro
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?

2020-03-01 Thread demotomohiro
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?

2020-03-01 Thread demotomohiro
[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

2020-02-25 Thread demotomohiro
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?

2020-02-25 Thread demotomohiro
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

2020-02-04 Thread demotomohiro
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

2020-02-02 Thread demotomohiro
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

2020-02-02 Thread demotomohiro
> 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

2020-01-20 Thread demotomohiro
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

2020-01-08 Thread demotomohiro
> -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

2020-01-03 Thread demotomohiro
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)

2019-12-09 Thread demotomohiro
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

2019-11-27 Thread demotomohiro
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?

2019-11-26 Thread demotomohiro
> 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

2019-11-20 Thread demotomohiro
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

2019-11-17 Thread demotomohiro
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

2019-11-12 Thread demotomohiro
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

2019-11-09 Thread demotomohiro
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?

2019-10-30 Thread demotomohiro
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?

2019-10-30 Thread demotomohiro
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)?

2019-10-24 Thread demotomohiro
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

2019-10-24 Thread demotomohiro
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

2019-08-01 Thread demotomohiro
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

2019-07-30 Thread demotomohiro
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)

2019-07-16 Thread demotomohiro
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

2019-07-02 Thread demotomohiro
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

2019-06-18 Thread demotomohiro
[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?

2019-05-15 Thread demotomohiro
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?

2019-05-14 Thread demotomohiro
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

2019-05-12 Thread demotomohiro
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 ?

2019-04-17 Thread demotomohiro
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

2019-03-11 Thread demotomohiro
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

2019-03-04 Thread demotomohiro
Thank you for notifyng me about that. I fixed the script and sent PR to Wandbox.


Re: Nim nightly builds

2019-02-16 Thread demotomohiro
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

2019-02-07 Thread demotomohiro
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

2019-02-05 Thread demotomohiro
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

2019-01-24 Thread demotomohiro
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

2019-01-23 Thread demotomohiro
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

2019-01-21 Thread demotomohiro
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

2019-01-20 Thread demotomohiro
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

2019-01-20 Thread demotomohiro
Thx!

But parsing json and finding URL I want to use only with bash script looks hard.


Re: Nim nightly builds

2019-01-16 Thread demotomohiro
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

2019-01-16 Thread demotomohiro
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

2018-12-04 Thread demotomohiro

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?

2018-11-05 Thread demotomohiro
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?

2018-10-24 Thread demotomohiro
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?

2018-10-10 Thread demotomohiro
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

2018-10-02 Thread demotomohiro
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

2018-09-25 Thread demotomohiro
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

2018-09-25 Thread demotomohiro
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?