Templates and imports

2020-02-26 Thread c0ntribut0r
Hello folks,

Does anyone know why templates don't "auto-import" symbols defined in their 
residence file? :( Minimal example:


# test.nim
import strutils

template test_template*() =
  echo (1.0/3.0).formatFloat(precision=3)

proc test_proc*() =
  echo (1.0/3.0).formatFloat(precision=3)


Run


# other.nim
import test

test_proc()  # ok
test_template()  # fail:
# /tmp/other.nim(4, 14) template/generic instantiation of `test_template` 
from here
# /tmp/test.nim(5, 17) Error: attempting to call undeclared routine: 
'formatFloat'


Run

Is it a new feature or a bug? I think it worked in a different way some time 
ago.


Nim Compiler Version 1.1.1 [Linux: amd64]
Compiled at 2020-02-25
git hash: db540a0223480134598fb4806c55510cdef36bf1


Run


Re: Nim Community Survey 2019

2020-02-20 Thread c0ntribut0r
Me too. Is opening an issue a contribution? Is writing a library a 
contribution? Also I liked to read raw responses as you posted in 2017 survey: 
[https://nim-lang.org/blog/2017/10/01/community-survey-results-2017.html](https://nim-lang.org/blog/2017/10/01/community-survey-results-2017.html)


Re: Raylib Forever (4Nim)

2020-02-10 Thread c0ntribut0r
Suggestion: now create a virus which will spread around the world and install 
everywhere a fully automated service to convert and deliver latest possible 
raylib headers, why not? Why your 4 previous wrapping attempts failed?


Re: Nimph is a Nim package handler for the rest of us

2020-01-14 Thread c0ntribut0r
Omg, my bad, i was searching for specific installation instructions before i 
wrote the comment, but i didn't see that section on Github -_- Maybe cause i 
expected "installation" to be before "usage".

Anyway, I'm sorry but calling bootstrap script is not something i expect from 
nimble package :(


Re: Nimph is a Nim package handler for the rest of us

2020-01-14 Thread c0ntribut0r
Well, after not finding it on nimble packages list... 


nimble install nimph
Prompt: nimph not found in any local packages.json, check internet for 
updated packages? [y/N]
Answer: y
Downloading Official package list
Success Package list downloaded.
   Tip: 3 messages have been suppressed, use --verbose to show them.
 Error: Package not found.


Run

...and after downloading all the dependencies... 


Downloading https://github.com/disruptek/nimph using git
  Verifying dependencies for nimph@0.6.14
  Info: Dependency on github@>= 1.0.2 already satisfied
  Verifying dependencies for github@1.0.2
  Info: Dependency on npeg@>= 0.20.0 already satisfied
  Verifying dependencies for npeg@0.22.2
  Info: Dependency on https://github.com/disruptek/rest.git@>= 1.0.0 
already satisfied
  Verifying dependencies for rest@1.0.3
  Info: Dependency on foreach@>= 1.0.0 already satisfied
  Verifying dependencies for foreach@1.0.2
  Info: Dependency on cligen@>= 0.9.41 already satisfied
  Verifying dependencies for cligen@0.9.41
  Info: Dependency on bump@>= 1.8.18 already satisfied
  Verifying dependencies for bump@1.8.19
  Info: Dependency on cligen@>= 0.9.40 already satisfied
  Verifying dependencies for cligen@0.9.41
  Info: Dependency on https://github.com/disruptek/cutelog@>= 1.1.2 
already satisfied
  Verifying dependencies for cutelog@1.1.2
  Info: Dependency on npeg@>= 0.21.3 already satisfied
  Verifying dependencies for npeg@0.22.2
  Info: Dependency on result@any version already satisfied
  Verifying dependencies for result@0.1.0
  Info: Dependency on https://github.com/disruptek/cutelog@>= 1.1.0 
already satisfied
  Verifying dependencies for cutelog@1.1.2
  Info: Dependency on https://github.com/disruptek/gittyup@>= 2.1.0 
already satisfied
  Verifying dependencies for gittyup@2.1.9
  Info: Dependency on nimgit2@0.1.1 already satisfied
  Verifying dependencies for nimgit2@0.1.1
  Info: Dependency on nimterop@>= 0.3.3 already satisfied
  Verifying dependencies for nimterop@0.3.3
  Info: Dependency on regex@>= 0.10.0 already satisfied
  Verifying dependencies for regex@0.13.0
  Info: Dependency on unicodedb@>= 0.7.2 already satisfied
  Verifying dependencies for unicodedb@0.7.2
  Info: Dependency on unicodeplus@>= 0.5.0 already satisfied
  Verifying dependencies for unicodeplus@0.5.1
  Info: Dependency on unicodedb@>= 0.7 already satisfied
  Verifying dependencies for unicodedb@0.7.2
  Info: Dependency on cligen@>= 0.9.17 already satisfied
  Verifying dependencies for cligen@0.9.41
  Info: Dependency on https://github.com/disruptek/results@1.0.0 
already satisfied
  Verifying dependencies for results@1.0.0
  Info: Dependency on 
https://github.com/stefantalpalaru/nim-unittest2@>= 0.0.1 already satisfied
  Verifying dependencies for unittest2@0.0.1
  Info: Dependency on regex@>= 0.11.0 already satisfied
  Verifying dependencies for regex@0.13.0
  Info: Dependency on unicodedb@>= 0.7.2 already satisfied
  Verifying dependencies for unicodedb@0.7.2
  Info: Dependency on unicodeplus@>= 0.5.0 already satisfied
  Verifying dependencies for unicodeplus@0.5.1
  Info: Dependency on unicodedb@>= 0.7 already satisfied
  Verifying dependencies for unicodedb@0.7.2
 Installing nimph@0.6.14


Run

... i get this


/tmp/nimble_2825/githubcom_disrupteknimph_#head/src/nimph/config.nim(11, 
16) Error: cannot open file: compiler/idents


Run

And yes, I have compiler==1.1.1


Re: grim - graph structures in Nim

2020-01-12 Thread c0ntribut0r
Thanks Erik for this lib. I'm curious why you store node attributes in 
heterogenous table. In compiled language i expect graph to be a generic with 
custom Node and Edge types known at compile time, smth like 


var g = newGraph[MyNodeType, MyEdgeType]()


Run


Re: Is there a 2D game framework recently updated for Nim ?

2020-01-02 Thread c0ntribut0r
[Cat 400](https://github.com/c0ntribut0r/cat-400) is in active development, but 
it's unstable yet and docs are outdated


Re: binarySearch (from algorithm) not always working

2019-12-16 Thread c0ntribut0r
Well then there should be an assert inside binarySearch which should check 
that. It will be deleted in release build anyway


Re: Why inherit RootObj?

2019-12-14 Thread c0ntribut0r
Disagreed. I use inheritance, methods and dynamic dispatch without RootObj.


Re: string to ptr uint8

2019-11-29 Thread c0ntribut0r
I guess you may replace input: ptr uint8 with input: cstring, isn't it the 
same? And then just pass nim string as usual.


Re: fileExists and existsFile. This made my day

2019-11-28 Thread c0ntribut0r
Haha @dom96, v1.0 is out...


Re: Pragmas Above Procs

2019-11-26 Thread c0ntribut0r
Could be something like this, as ugly as original pragmas :>


foo(callback = [closure, gcsafe] proc() = echo "baa")


Run


Re: "out of memory" when creating new Thread inside sharedTable lock

2019-11-26 Thread c0ntribut0r
Workaround with pointer to table and custom lock ¯_(ツ)_/¯ 


import tables
import strformat
import os
import typetraits
import locks


type
  ThreadName = string
  ThreadInfo = object
thread: Thread[ThreadName]


var threads = initTable[ThreadName, ThreadInfo]()
let threadsPtr = threads.addr
var threadsLock: Lock
threadsLock.initLock()


proc threadEntrypoint(name: ThreadName) {.thread.} =
  while true:
echo &"Inside thread: name={name}"


proc spawn(name: ThreadName) =
  echo &"Spawning: name={name}"
  
  withLock threadsLock:
if name in threadsPtr[]:
  raise newException(ValueError, "Thread with this name was already 
registered")

threadsPtr[][name] = ThreadInfo()
threadsPtr[][name].thread.createThread(param=name, tp=threadEntrypoint)
echo &"Created thread: name={name}"


when isMainModule:
  spawn(name="a")
  spawn(name="b")
  
  sleep(1000)


Run


Re: "out of memory" when creating new Thread inside sharedTable lock

2019-11-25 Thread c0ntribut0r
Thanks for testing it!

I tried different combinations for writing thread instance to sharedTable. 
Seems that creating temporary variable may help, but other cases simply don't 
work:


import sharedtables
import strformat
import os
import typetraits


type ThreadInfo = object
  thread: Thread[void]


var threads: SharedTable[string, ThreadInfo]
threads.init()


proc threadEntrypoint() {.thread.} =
  while true:
echo "OK"


when isMainModule:
  let key = "key"
  
  # 1) works (well, if it didn't work nim would worth nothing)
  
  var value = ThreadInfo()
  value.thread.createThread(tp=threadEntrypoint)
  
  
  
  # 2) illegal storage access
  
  threads.withKey(key) do (key: string, value: var ThreadInfo, pairExists: 
var bool):
if pairExists:
  raise newException(ValueError, "Thread with this name was already 
registered")

value = ThreadInfo()
value.thread.createThread(tp=threadEntrypoint)

pairExists = true
  
  
  
  # 3) works
  
  threads.withValue(key, value) do:
echo "Value already exists"
  do:
var info = ThreadInfo()
info.thread.createThread(tp=threadEntrypoint)
threads[key] = info
  
  
  
  # 4) hangs forever
  
  threads.withValue(key, _) do:
echo "Value already exists"
  do:
threads[key] = ThreadInfo()
threads.mget(key).thread.createThread(tp=threadEntrypoint)
  
  
  
  sleep(1000)


Run


"out of memory" when creating new Thread inside sharedTable lock

2019-11-25 Thread c0ntribut0r
Hello guys! I need your help, cannot figure out wtf is going on here.

I made a minimal example which produces an "out of memory" error. The idea is 
simple: create a "spawn" proc which

  1. accepts a name (just a string)
  2. runs some dumb thread
  3. adds mapping to shared table: name -> thread



Since I use shared table, each thread can (safely, due to lock) access other 
thread information using thread's name.

Here is the code: 


import sharedtables
import strformat
import os
import typetraits


type
  ThreadName = string
  ThreadInfo = object
thread: Thread[ThreadName]
# ... and some other info (channel etc)


var threads: SharedTable[ThreadName, ThreadInfo]
threads.init()


proc threadEntrypoint(name: ThreadName) {.thread.} =
  echo &"Inside thread: name={name}"


proc spawn(name: ThreadName) =
  echo &"Spawning: name={name}"
  
  threads.withKey(name) do (key: ThreadName, value: var ThreadInfo, 
pairExists: var bool):
if pairExists:
  raise newException(ValueError, "Thread with this name was already 
registered")

echo &"withKey: name={key}"

value = ThreadInfo()
echo &"Creating thread: name={key}"
value.thread.createThread(param=key, tp=threadEntrypoint)
echo &"Created thread: name={key}"

pairExists = true


when isMainModule:
  spawn(name="a")
  
  sleep(1000)



Run

The output is really surprising, I cant google something similar and it's even 
not an exception:


Spawning: name=a
withKey: name=a
Creating thread: name=a
Created thread: name=a
out of memory


Run

It's probably something related to shared table lock and spawning a thread 
during this lock (but im not sure). I tried different ways to fill that shared 
table with spawned threads but didn't succeed.


Re: Advantages of "from... X... import Y" over "import Y"?

2019-11-21 Thread c0ntribut0r
This is an excellent article imho 
[https://narimiran.github.io//2019/07/01/nim-import.html](https://narimiran.github.io//2019/07/01/nim-import.html)


Re: Nim based Github Actions

2019-11-15 Thread c0ntribut0r
Very handy, thanks a lot!


Re: code to unpack (msgpack) and "cast" object to

2019-10-28 Thread c0ntribut0r
There you go 
[https://github.com/c0ntribut0r/cat-400/blob/master/c4/messages.nim](https://github.com/c0ntribut0r/cat-400/blob/master/c4/messages.nim)


Logging milliseconds

2019-10-28 Thread c0ntribut0r
Hello everyone,

How do I make logging output milliseconds? Default formatting options are 
rather conservative in terms of date/time:


Format strings support the following variables which must be prefixed with 
the dollar operator (``$``):
$date Current date
$time Current time
$datetime $dateT$time


Run

I can't even define my logging subclass cause 
[substituteLog](https://github.com/nim-lang/Nim/blob/master/lib/pure/logging.nim#L103)
 is a proc, not method >:(


proc substituteLog*(frmt: string, level: Level, args: varargs[string, 
`$`]): string =
  # ...
  case v
  of "date": result.add(getDateStr())
  of "time": result.add(getClockStr())
  of "datetime": result.add(getDateStr() & "T" & getClockStr())


Run

I guess I have to redefine log method but it's a bit ugly solution. Any chance 
to make logging more configurable?


Re: Nimble cannot find latest version of package

2019-03-19 Thread c0ntribut0r
Thanks! It's all clear now.


Re: How to force destroy a ref?

2018-09-23 Thread c0ntribut0r
Thank you! You described my problem in more general and more meaningful way! 
I'm not familiar with C# but I liked the Disposable idea. Now I'll follow your 
advice and will separate "physical" (=destroy()) and "logical" (dispose()) 
destruction of object.

I love nim community :)


How to force destroy a ref?

2018-09-23 Thread c0ntribut0r
Is there any way to destroy a `ref` manually? My object has


proc `destroy=`(self: Figure) =
  gui.eraseFigure(self.handler)


Run

So when object is garbage collected, it is erased on screen as well. However, 
object is not collected immediately, so I still see it on screen after removing 
all references to it. Only when GC comes to the object and destroys it, the 
object disappears, but it may take significant amount of time.

Is there any possibility to say "hey, GC, take a look at this object - it has 
no references anymore, please collect it asap"?


Re: How to get the address of string ""

2018-05-08 Thread c0ntribut0r
If you're using FFI and the proc accepts cstring type, you don't even need to 
convert string to cstring at all:


proc printf(formatstr: cstring) {.importc: "printf", varargs, header: 
"".}
printf("This works %s", "as expected")



Re: How to get the address of string ""

2018-05-08 Thread c0ntribut0r
I'm not sure, but here b should contain ptr to empty string - am I right?


var a = ""
let b = a.cstring
echo $cast[int](b)


But why do you need this?


importc and dynamic name resolution

2018-04-22 Thread c0ntribut0r
Some library's C API functions look like this:


h3dAddResource
h3dDelResource
...


In my nim wrapper I use:


{.push dynlib:lib, importc:"h3d$1".}
proc AddResource(...)
proc DelResource(...)
{.pop.}


This appends "h3d" before proc name for C API. How can I also make proc names 
start with lower letters in bulk? Maybe there's a way to pass a translation 
proc? This would be perfect:


{.push dynlib:lib, importc:proc(nimName: string): string = "h3d" & 
nimName[0].toUpperAscii() & nimName[1..^nimName.len]}
proc addResource(...)
proc delResource(...)



Re: Why macros can't find a local module?

2018-04-01 Thread c0ntribut0r
Heres a [macro for importing by 
string](https://forum.nim-lang.org/t/3547/1#22257), try it out


Re: proc(t: typedesc): var t -- expected 'None' error

2018-03-29 Thread c0ntribut0r
Thank you guys! I stayed with templates, don't know why I didn't use them from 
the beginning.

But typedesc[T] is really, really evil and black magic:


proc getMutableVal[T](key: int, desc: typedesc[T]): var T =
  getTableOf(T)[key]



proc(t: typedesc): var t -- expected 'None' error

2018-03-27 Thread c0ntribut0r
I'm trying to simplify my program syntax by creating nice aliases. Cannot 
understand what's wrong when returning var t where t is typedesc:


import tables

proc getTableOf*(t: typedesc): ref Table[int, t] =
  var table {.global.} = newTable[int, t]()
  return table

proc getVal(key: int, t: typedesc): t =  # just an easy accessor (alias)
  getTableOf(t)[key]

# check they are the same
getTableOf(bool)[0] = false
assert 0.getVal(bool) == getTableOf(bool)[0]  # for key "0", lookup value 
in boolean table - this works
echo "ok"


proc getMutableVal(key: int, t: typedesc): var t =
  getTableOf(t)[key]

getTableOf(bool)[0] = false  # get boolean table, select mutable value by 
key - this works!
0.getMutableVal(bool) = false  # same: for key "0", get mutable value from 
boolean table
# ^-- Error: type mismatch: got  but expected 'None'
assert 0.getVal(bool) == false
echo "ok"


Please help! :/


Re: How to (de)serialize inherited object?

2018-03-23 Thread c0ntribut0r
In case anyone will ever need inheritance support for msgpack: 
[https://github.com/c0ntribut0r/cat-400/tree/master/c4/wrappers/msgpack](https://github.com/c0ntribut0r/cat-400/tree/master/c4/wrappers/msgpack)


Re: How to (de)serialize inherited object?

2018-03-21 Thread c0ntribut0r
Probably there's no easy solution of this task

[Same for c++ on Stack 
Overflow](https://stackoverflow.com/questions/3268801/how-do-you-de-serialize-a-derived-class-from-serialized-data)

[Comprehensive 
guide](https://isocpp.org/wiki/faq/serialization#serialize-inherit-no-ptrs)


Re: How to (de)serialize inherited object?

2018-03-21 Thread c0ntribut0r
It would be too easy! 


import streams, nesm

serializable:
  type
TA = object of RootObj
TB = object of TA
  f: int

var
  a: ref TA
  b: ref TB

new(b)
a = b

echo stringify(serialize(a))



lib/nim/system.nim(2833, 7) Error: unhandled exception: kind(thetype[1]) == 
nnkEmpty
 Inheritence not supported in serializable



Re: how to read/write object from/to binary file?

2018-03-21 Thread c0ntribut0r
Have a look at this:


import streams
type
  MyType* = object
somefield*: array[10, int16]
var t1, t2: MyType
t1.somefield[0] = 1
t2.somefield[0] = 2


var f = newFileStream("/tmp/tmp.mytype", fmWrite)
if not f.isNil:
  f.write t1
  f.write t2
f.flush

var r1, r2: MyType
var f2 = newFileStream("/tmp/tmp.mytype", fmRead)
discard f2.readData(r1.addr, r1.sizeof)
discard f2.readData(r2.addr, r2.sizeof)
echo r1.somefield
echo r2.somefield



How to (de)serialize inherited object?

2018-03-21 Thread c0ntribut0r
Hello guys,

Is there any way to serialize object including its runtime type data? Both 
[marshal](https://nim-lang.org/docs/marshal.html) and 
[msgpack4nim](https://github.com/jangko/msgpack4nim#ref-types) don't support it 
out-of-box.


import streams, msgpack4nim

type
  TA = object of RootObj
  TB = object of TA
f: int

var
  a: ref TA
  b: ref TB

new(b)
a = b

echo stringify(pack(a))
#produces "[ ]" or "{ }"
#not "[ 0 ]" or '{ "f" : 0 }'


I know about object variants but if I use them I will lose the elegance of 
dynamic dispatch and will have to write those ugly


case obj.kind
  of kndA:
# 50 lines of code
  of kndB:
# another 50 loc
  # ... etc


One possible solution is to write a macro that will pack class name together 
with the data, like


genPackers(TA, TB, TC, ...)
# transforms into:
method pack*(a: ref TA): string =
  pack "TA"  # specify runtime type as string
  pack a

method pack*(b: ref TB): string =
  pack "TB"
  pack b

proc unpack*(data: string): ref TA =
  var typ: string = unpack(data)
  case typ
of "TA":
  result = unpack[TA](data)
of "TB":
  result = unpack[TB](data)
# ...



This will probably work, but is there a better solution, without strings of 
class names and lising all possible classes? Kinda


proc pack(anything: ref TA): string =
  pack(anything.runtimeType)  # pack internal type info
  pack[anything.runtimeType](anything)  # pack the object with respect to 
its runtime type

proc unpack(data: string): ref TA =
  let runtimeType = unpack[typeInfo](data)  # unpack runtime type
  result = unpack[runtimeType](data)  # unpack data according to that 
runtime type



Defining variable in nim.cfg

2018-03-11 Thread c0ntribut0r
Hello, I have a long compilation command like this:


nim c -r -o=../build -d:myUglyVariable:"myUglyValue" main.nim 
--loglevel=DEBUG


I'd like to move all that in nim.cfg, or at least that ugly variable, so that I 
type just 


nim c -r main.nim


Is that possible? I really lack any docs on nim.cfg file syntax.


Re: Resources embedding

2018-03-04 Thread c0ntribut0r
Not an expert, but afaik string is just a sequence of chars and char is always 
a byte. Thus you just staticRead and then may access each byte using subscript 
[]. Haven't heard about other ways of dancing with bytes in nim :/


Re: Has anyone else been bitten by this?

2018-02-16 Thread c0ntribut0r
At my (newbie's) point of view, you're right - conversion makes n being an 
expression. This wouldn't be a problem if there was overloading resolution by 
return type and you wouldn't need to use those x: var int8, but there's no hope 
[https://forum.nim-lang.org/t/3025](https://forum.nim-lang.org/t/3025)


Re: Get location of nimcache folder at compile time

2018-02-16 Thread c0ntribut0r
The only thing I found is that nimscript function  What's the use-case btw? I 
found the rule: when I try to do smth and there's no easy solution for it -> 
probably my code smells and I'm doing smth totally wrong  Why do you ever need 
to touch the cache?


Re: Import module by name / absolute path

2018-02-15 Thread c0ntribut0r
That's why I like nim! Got a reply on my questions in 5 minutes from Araq!  
Thank you


Re: Get location of nimcache folder at compile time

2018-02-14 Thread c0ntribut0r
Maybe system.nimscript.nimcacheDir() may help?

[See 
github](https://github.com/nim-lang/Nim/blob/08950649839c1df1504d495fccfea04bf11f55ed/lib/system/nimscript.nim#L246)


Import by

2018-02-14 Thread c0ntribut0r
Consider I have these modules which define the same functions (only 
implementation differs): 


-math_precise.nim
-math_optimal.nim
-math_fast.nim


Now I want to include them based on compile-time option.

I know I can use


const math {.strdefine.}: string = "precise"  # default value
when math == "precise":  # <-- here I hardcode possible values
  import math_precise
elif math == "fast":
  import math_fast


And then 


nim c -d:math:fast


1) What if I don't want to hardcode modules names and just import by name? Like 


const math {.strdefine.}: string = "precise"  # default value
import "math_" & math  # <-- Error: invalid module name :( I guess I should 
play with macros?


2) Also, is there any way to import module by absolute location? 


import /tmp/math_superfast


3) Will things work if I use "include" instead of "import"? (I know the 
difference between them) 


Re: Dynamic dispatch and star wars

2018-01-21 Thread c0ntribut0r
@mashingan Yeah, that's true. However, the proposed idea would be a very 
comfortable way to override library's methods. But because of UB now user has 
to pass either subclass with custom methods or pointers to procs to the library 
which I find a bit messy.

Imagine a math library which does some calculations. Inside it there's a method 
to calculate square root. One day user understands that he knows a better and 
faster square root implementation. How can he "inject" it there? Currently 
there's no way unless lib authors allow him (in advance) to use some setting 
like sqrt = ref proc(x: float): float

P.S. I came from Python so static programming languages are big pain for me 


Re: Dynamic dispatch and star wars

2018-01-21 Thread c0ntribut0r
Thank you!

Yeah you got the idea! Compiler doesn't allow to redefine a proc/method in the 
same module, however **redefinition across modules compiles fine**. I wanted to 
use this trick to allow users redefine my library methods in their code - just 
like that kill in main.nim. It is much simpler than using inheritance or other 
methods to inject user-defined code - just use internal dispatch trees that 
will do all redefinition job for you 

Undefined behaviour here is really undefined. What made me curious is that 
definition order is always the same (kill from main.nim is always defined 
last), but dispatch depends on other non-related methods which is 
counter-intuitive...

P.S. Thanks for var notice. Actually it is a part of a larger codebase where 
the reassignment really happens. I just omitted some unnecessary code.


Dynamic dispatch and star wars

2018-01-20 Thread c0ntribut0r
Okay guys, this is something that blows my mind away! I've wiped everything 
redundant from my code and added Star Wars to make it funnier, but the problem 
is really terrifying me.

Consider we have a class Hero and a method for a Hero to kill another Hero: 


# heroes.nim
type
  Hero* = object of RootObj

method kill*(self: var ref Hero, victim: ref Hero) {.base, inline.} = 
discard
# by default no one can kill another Hero. kill() just does nothing


Now we create a bit of Jedi: 


# jedi.nim
import heroes

type
  OB1* = object of Hero
  Yoda* = object of Hero

method kill*(self: var ref Hero, victim: ref OB1) = echo("Obi Wan Kenobi 
was killed")
method kill*(self: var ref Hero, victim: ref Yoda) = echo("Yoda was killed")
# Even Jedi may be killed!


For the sith, let's add a Startrooper. I never liked them so we won't use it 
anywhere. However, its role is significant! (see below) 


# sith.nim
import heroes

type
  Startrooper* = object of Hero

method kill*(self: var ref Hero, victim: ref Startrooper) = 
echo("Startrooper was killed... one more")


Now let's play! 


# main.nim
import heroes

import jedi
# import sith  # <-- leave for now

# this method will protect Yoda from being killed by anyone
method kill(self: var ref Hero, victim: ref Yoda) = echo("Yoda may not be 
killed!")

var
  darthVader = new(ref Hero)
  yoda = new(ref Yoda)

# this call matches exactly the newly defined method above
darthVader.kill(yoda)  # outputs "Yoda may not be killed!", as expected


Now we add sith... 


# main.nim
import heroes

import jedi
import sith  # <-- uncomment this
# this method will protect Yoda from being killed by anyone
method kill(self: var ref Hero, victim: ref Yoda) = echo("Yoda may not be 
killed!")

var
  darthVader = new(ref Hero)
  yoda = new(ref Yoda)

# this call matches exactly the newly defined method above
darthVader.kill(yoda)  # outputs "Yoda was killed"... WAT?!


Do you see it too? We added a method to kill a Startrooper (method kill(self: 
var ref Hero, victim: ref Startrooper)) and suddenly our Yoda's protection is 
broken! What the hell?!

Now leave sith module included and let's comment killing Obi Wan Kenobi: 


# jedi.nim
import heroes

type
  OB1* = object of Hero
  Yoda* = object of Hero

# method kill*(self: var ref Hero, victim: ref OB1) = echo("Obi Wan Kenobi 
was killed")
method kill*(self: var ref Hero, victim: ref Yoda) = echo("Yoda was killed")


Guess what?! "Yoda may not be killed!"

So, when you add sith module with Startrooper killing, Yoda's protection 
becomes broken, but when you make Kenobi immortal, Yoda's protection is back!

Now here's the question: how close to schizophrenia I am?


Re: Understanding staticRead's weird behaviour

2018-01-15 Thread c0ntribut0r
Oh, thank you all. Didn't know that readFile requires ffi...  Nim looks so 
easy but the deeper you dive the more complex it is.


Understanding staticRead's weird behaviour

2017-12-13 Thread c0ntribut0r
Hello nim lovers! Another portion of dumb questions from nim newbie 

1) Consider this project structure: 


app.nimble
app/
   - version.txt  # contains "0.1.1-3"
   - utils.nim


utils.nim contains getVersion helper which just reads from file: 


proc getVersion*(versionFile:string): seq[string] =
  staticRead(versionFile).split('-')  # static is required because I need 
this value at compile time


app.nimble: 


const
  versionFile = "app/version.txt"
# ...
task version, "Get version":
  echo "Proc call: " & $(getVersion(versionFile))
  echo "Inline call: " & $(staticRead(versionFile).split('-'))


Now here is the magic: 


> nimble version
  Executing task version in .../app.nimble
Proc call: @[0.1]  <-- WTF?!
Inline call: @[0.1.1, 3]


Okay, it looks like calling staticRead is cached somehow when using a proc 
(cause I had "0.1" some time ago). But why, and how to avoid it?

2) My versionFile must be defined **relative to `utils.nim` location** because 
that's where staticRead resides. If I move utils somewhere else, I would need 
to change versionFile's path which is absolutely terrible!

3) Also, just curious why we have to use staticRead at all? Looks like const 
already marks expressions as compile-time: 


const
  constEval = contains("abc", 'b') # computed at compile time, no need to 
use staticContains or smth
  data = readFile("somefile")  # <-- OOPS! doesn't work at compile time
  data = staticRead("somefile")  # <-- will work


Cannot nim distinguish between compile/runtime and call appropriate read 
function accordingly?