Re: Help understanding simple string pointer indexing example

2020-04-24 Thread ggibson
I'm ambivalent about that issue of not knowing where things are defined in nim. 
On the one hand, I like how clean the code reads without fully qualifying procs 
from their modules. On the other, if I don't have complete knowledge of all 
modules, then I've little idea where a particular proc/template/iterator comes 
from. The only palliative suggestion I've heard is to "use a better IDE". shrug


Re: Help understanding simple string pointer indexing example

2020-04-24 Thread ggibson
Fantastic explanation; Thank you so much for taking the time to explain this 
and look into the issue. I had forgotten that, of course, strings are smart 
objects that check their length, and have a `setLen()` for cases like this. 
:facepalm:

Humorously, I wrote an entire tool predicated on my faulty knowledge, have been 
using it in production, and only discovered there were issues when one day I 
tried to compile with the arc GC, which told me I was doing something naughty 
with memory. :p


Re: Help understanding simple string pointer indexing example

2020-04-22 Thread ggibson
Maybe manually allocated strings like this can only be achieved using 
UnchedArray[char]?


# test.nim
proc main =
  let str = "hello"
  var sptr = UncheckedArray[char].create(str.len)
  for i in 0 ..< str.len:
sptr[][i] = str[i]
  echo sptr[]

when isMainModule:
  main()


Run


Re: Help understanding simple string pointer indexing example

2020-04-22 Thread ggibson
@juancarlospaco Thanks. Yes, that's the error message. But I'm using `create`, 
which the docs state:


create(): The block is initialized with all bytes containing zero,
  so it is somewhat safer than createU.


Run

and I can definitely use `copyMem` with the allocated memory region. I'm still 
at a loss.


Help understanding simple string pointer indexing example

2020-04-22 Thread ggibson
Hi, I'd appreciate help understanding why the below example fails. Thanks for 
looking!


# test.nim
proc main =
  let str = "hello"
  var sptr = string.create(str.len)
  #copyMem(sptr, unsafeAddr str, str.len) # this works
  #sptr[] = str # this also works
  # but let's try manual copy
  for i in 0 ..< str.len:
sptr[][i] = str[i]
  echo sptr[]

when isMainModule:
  main()


Run

Output


Error: unhandled exception: index out of bounds, the container is empty 
[IndexError]


Run

Nim 1.2.0, `nim c test.nim`


Thank you Templates

2020-02-27 Thread ggibson
I just wanted to say this language is fantastic. I just finished a -- to me -- 
medium-sized project for work yesterday that took about a week (including 
modifying & wrapping a C library to replace `httpclient` for static compiling 
with SSL/TLS, but that's another story...) and I had decided to use the 
`argparse` module. Having never used it before, I didn't realize there are so 
many bugs in `argparse` that I needed duplicate code, have an extra page of if 
statements, and several loops to "fix" the parameters before `argparse` even 
saw it to keep it from crashing. My point is sometimes code has issues and 
isn't a perfect fit for ever use case - no fault of the `argparse` author - 
it's awesome it exists.

Speaking of perfect fit for my use case, today I decided to replace `argparse` 
with good old `parseopt` from the standard library. `parseopt` is a little low 
level, but with less than 20 LOC across 2 simple templates, I had a lean CLI 
framework that did exactly what I wanted. Using this new code ended up reducing 
my overall LOC by about 65! Not to mention, the arguments parsing became _way_ 
easier to read.

Thank you Nim, Nim community; I'm having fun.

For the curious, here are my templates. Perhaps not best practices are seen 
here, but it's working for what I need so far, and the code is much more 
maintainable. (In hindsight, `docopt` would have also worked and saved even 
more code at the trade-off of dependencies, and been a bit restrictive on the 
help text. Next time!) 


# register_command(word) creates two variables: word_args:seq[string] and 
word_enabled:bool
# that are automatically set and filled for you
template register_command(command:untyped, nargs:Natural = 0, 
aliases:openArray = new_seq[string]()) {.dirty.} =
  when not defined(`command`):
let `command` :string = ""
  var
`command _ args` {.used.} = new_seq[string]()
`command _ enabled` = false
`command _ args _ len` {.used.} = nargs
`all _ command _ alias _ list`:seq[string] # [command, alias1, alias2, 
...]
  if aliases.len > 0:
`all _ command _ alias _ list` = 
concat(@[`command`.astToStr],to_seq(aliases))
  else:
`all _ command _ alias _ list` = @[`command`.astToStr]

template capture_command(p:OptParser, command:untyped) {.dirty.} =
  if p.key in `all _ command _ alias _ list`:
`command _ enabled` = true
for capture_command_i in 1 .. `command _ args _ len`:
  p.next()
  if p.kind == cmdEnd: break # assume we're using parseopt while loop 
convention
  `command _ args`.add p.key
continue

## register all cli arguments
when defined(windows):
  register_command(vs)
register_command(force,aliases=["f"])
register_command(init)
register_command(cxx,nargs=1,aliases=["c"])
register_command(debug,aliases=["g"])
register_command(generate,nargs=1,aliases=["gen"])
register_command(new,nargs=2)
register_command(copy,nargs=3,aliases=["cp"])
register_command(download,nargs=1,aliases=["dl"])
register_command(help,aliases=["h"])

# meanwhile, in main()...
proc main() =
  
  # parse the command line options
  var p = initOptParser(command_line_params())
  while true:
p.next()
case p.kind:
  of cmdEnd: break
  of cmdShortOption, cmdLongOption:
p.capture_command force
p.capture_command cxx
p.capture_command help
write_error("Error: ",&"Unknown command or option '{p.key}'")
quit(1)
  of cmdArgument:
p.capture_command new
p.capture_command copy
p.capture_command download
p.capture_command generate
p.capture_command init
when defined(windows):
  p.capture_command vs
write_error("Error: ",&"Unknown command or option '{p.key}'")
quit(1)
  
  if help_enabled:
echo help_text
quit(0)
  
  # etc.


Run


Re: Paranim and Pararules - my new gamedev libraries

2020-02-18 Thread ggibson
Re: Pararules; Very nice! Thank you for sharing. I'll be playing with and 
checking in on this.


Re: Why does `k in t.keys.toSeq.sorted` works but `k in t.keys.toSeq.sorted()` does not.

2020-02-18 Thread ggibson
I forgot I was going to say, the fix is something like:


for k in toSeq(t.keys).sorted():


Run


Re: Why does `k in t.keys.toSeq.sorted` works but `k in t.keys.toSeq.sorted()` does not.

2020-02-18 Thread ggibson
This is a common problem, but a sneaky one! It's because toSeq is not a proc, 
but a template. Because of the parser for templates, that means toSeq must be 
fully qualified and the sorted() messes this up for some reason. I'm going to 
quote someone else's answer very much related to this:

@twetzel59 Dec 2018


How does resize(ptr, size):ptr work?

2020-02-18 Thread ggibson
Like many people, I made my own seq-like purely as an exercise to understand 
how Nim low-level memory management works. I was excited to find in the docs 
the `create` and `resize` procs, but `resize` eludes me. It doesn't appear to 
do much. Below is my minimum example with a working version using `create` and 
one that doesn't work with `resize`. Also, where can I read the source for 
`realloc`? [This line in 
system.nim](https://github.com/nim-lang/Nim/blob/89b39ee8fe271d0e1b75c15a4c6cf82eb9c13aea/lib/system.nim#L2426)
 is as far as I got - looks like a forward declaration?


# nim --version 1.1.1 2020-02-15 (devel)
# GCs: only ``none`` and ``refc`` allow the manual method below to work okay
# ``boehm`` and ``arc`` produce corrupted memory (if I'm doing it right)
# I use compile-time defines to switch between the two methods

import strformat

type MyArray[T] = object
  data:ptr UncheckedArray[T]
  len:Natural
  reserved:Natural

proc newMyArray[T]():MyArray[T] =
  result.reserved = 32
  result.len = 0
  result.data = create(T=UncheckedArray[T], size=result.reserved)

proc append[T](self:var MyArray[T],val:T) =
  if unlikely(self.len == self.reserved):
when defined(debug):
  echo &"Allocating new memory {self.reserved} to {self.reserved shl 1}"
self.reserved = self.reserved shl 1

when defined(manual):
  var newmem = create(T=UncheckedArray[T], size=self.reserved)
  copyMem(newmem, self.data, sizeof(T)*self.len)
  dealloc self.data
  self.data = newmem

when defined(fancyresize):
  var newmem = resize(self.data, self.reserved)
  # cast[int](self.data) is same before and after resize() call
  # self.data now corrupted
  #cast[int](newmem) is always 0
  
  self.data[self.len] = val
  inc self.len

proc `$`[T](self:MyArray[T]):string =
  result = "["
  for i in 0..

Re: Help needed: Nested lists in Nim

2019-11-19 Thread ggibson
Yes, this. Related questions pop up every year in our algorithms courses, and 
the wonders of the modern CPU cache always amaze students!


Re: procs operating on concepts?

2019-04-04 Thread ggibson
Ah, okay. Thank you both for the clarification.


procs operating on concepts?

2019-04-03 Thread ggibson
How can I have a function that returns a subset copy of a collection of things 
that always have a certain property? The following doesn't work, but shows my 
intent with concepts. It works if I use `openArray[Agent]` explicitly instead 
of a concept.


import sequtils, random, algorithm, itertools

type
  Agent = object
score:float
  Scorable = concept x
x.score is float
  ScorableCollection = concept x
x[0].score is float
x is seq[Scorable]

proc roulette_wheel(agents:ScorableCollection, N:int):auto =
  proc sum(a,b:float):float = a+b
  var wheel = toSeq: agents . mapIt(it.score) . accumulate sum
  result = N . newSeqWith agents[ wheel . lowerBound rand wheel[^1] ]

var agents = newSeqWith(10, Agent(score:random(1.0)))
echo roulette_wheel(agents, 2)


Run


Re: macros to generate class

2019-03-31 Thread ggibson
There's no easy answer, but you can do it yourself without a huge amount of 
work. Check out this blog post [on writing nim 
macros](https://flenniken.net/blog/nim-macros/) and use the dumpAstGen macro to 
show you how to make what you want. Happy learning!


Status / Decision for seqUtils overhaul?

2019-03-29 Thread ggibson
I ran across this thread while searching for various functionality, and 
wondering where to submit a PR if I add some.

[Changes in sequtils (forum post)](https://forum.nim-lang.org/t/1333)

I'm curious if anyone knows if these suggested changes and additions are still 
under consideration, or if it was decided to let them remain in an external 
repository (nimLazy), and what are people using if they want any of these 
features? There seem to be some great relevant packages out there all 
overlapping to a large degree, but not interoperable: 
[nimLazy](https://github.com/petermora/nimLazy), 
[itertools](https://github.com/narimiran/itertools), 
[pipe](https://nimble.directory/pkg/pipe), 
[mangle](https://github.com/baabelfish/mangle), and maybe others I didn't find.


Re: Is it possible to add a proc after a proc in a macro?

2019-03-16 Thread ggibson
Then definitely check out the memo module, because it shows how you create, 
copy, and rename procs in a macro.


Re: Is it possible to add a proc after a proc in a macro?

2019-03-16 Thread ggibson
I think Steve Flenniken covers this or something very close to it in his [blog 
post about nim macros](https://flenniken.net/blog/nim-macros/)


Help upgrading macro to work in compileTime context

2019-03-16 Thread ggibson
I'm stuck at the following. Is there maybe a way to detect that I'm resolving a 
macro for a compileTime context rather than a runtime context?

I'm trying to upgrade the memo module. Normally, if memoizing in a runtime 
context, like the following, then the cache is initialized as such. 


proc complexProc(n:int):int {.memoized.} =
  # this is recursive...
...
proc main() =
  var fastResult = complexProc(46)
  echo fastResult


Run

Cache initialized in `memoized()` macro:


...
  var cache = initTable[argType, retType]() # this is runtime-only declared
  ...


Run

Okay, now if I want this to work in a compileTime context, I just change `var 
fastResult` to `const fastResult`: 


proc complexProc(n:int):int {.memoized.} =
  # this is recursive...
...
proc main() =
  const fastResult = complexProc(46)
  echo fastResult


Run

BUT! I must change cache initialization to be `compileTime`, which now makes it 
unworkable for runtime contexts:


...
  var cache {.compileTime.} = initTable[argType, retType]() # this is 
compileTime-only declared
  ...


Run

So, what kind of when/if statement should be there? I can't use `when nimvm` 
because it's always in nimvm.

Alternatively, I could do the macro equivalent of a global cache if I ensure 
unique ident, but I don't like that I have to check for initialization on every 
call and can't rely on `{.global.}` to do the right thing at `compileTime`. 
Perhaps this is simply the way to go and settle for the extra if statement 
penalty.

Caching that works in both compileTime and runtime contexts: 


proc complexProc(n:int):int =
  var cache {.global.}:Table[int,int]() # with the if, works in compileTime 
and runtime contexts
  if len(cache) == 0: cache = initTable[int,int]()
  # usual recursive code


Run


Re: Can I access arrays faster than this?

2019-03-07 Thread ggibson
@cblake True, true. I was simply enjoying that I could write "one through 
fifty, so fifty times" very simply and easy to read in nim, whereas I just 
relied on trained C eyes to interpret the C code of its intended meaning "zero 
up until 50, meaning 50 times". Perhaps nim's `countup()` would have been even 
more appropriate.

@Stefan_Salewski You're making fun of my specific example! :) Yes adding `i32` 
wasn't that cumbersome in THAT example, but I'm sure you could imagine 
scenarios where it would get more annoying - this was only an illustration of 
how it works. Also, you have to be sure that you didn't miss one, not to 
mention you'll already have to annotate by hand any relevant var types in the 
signature since the macro doesn't handle that part.


Re: Can I access arrays faster than this?

2019-03-06 Thread ggibson
My current extension of @Araq's macro looks like this:


import macros, typetraits

proc replace(n: NimNode; typesrc,typedst: typed; kndsrc,knddst: 
NimNodeKind): NimNode =
  if n.kind == kndsrc:
when not defined(release): echo "replacing ",n.repr," with ",knddst
result = newNimNode(knddst)
case kndsrc:
of nnkFloatLit: result.floatVal = n.floatVal
of nnkIntLit: result.intVal = n.intVal
else: discard
  elif n.repr == typesrc.repr:
when not defined(release): echo "replacing ",n.repr," with 
",typedst.repr
result = newIdentNode(typedst.repr)
  else:
result = copyNimNode(n)
for i in 0..

Re: Can I access arrays faster than this?

2019-03-06 Thread ggibson
> While Araqs example macro is very interesting, I strongly assume that 
> performance impact of float literal types is only minimal in most cases.

But that's for floats, perhaps. The only reason I went down that road is 
because I found a noticeable speedup by putting `'i32` and `int32` everywhere, 
but it was easy to miss decorating a literal and made the code visually very 
messy.

The example is the first post code but with N=100 million, and I run that exe 
10 times. On my machine c++ (int32) takes about 7.5 seconds per run, and nim 
(int64) 8.5 seconds per run. If I liberally `i32` decorate, then nim becomes 
identical to the c++ version in runtime.

With @cblake's suggestion, I tried `-march=native` and/or `-mavx` with no 
benefit for me.


Re: Can I access arrays faster than this?

2019-03-05 Thread ggibson
> * The Nim code isn't in a main procedure
> 
> * The C++ code is using int s (32 bits) while Nim is using int s (64 bits). 
> Nim's int type is always the size of a pointer, so you can use it for 
> indexing arrays. The difference in size between those types means that the 
> Nim program is processing twice as much data.

The 32 bit / 64 bit made a noticeable difference - that was an excellent 
suggestion. I looked around for a nice way to enforce changes to all my 
literals and types, and found an example 
[here](https://forum.nim-lang.org/t/1267#19038) by @Araq that I've modified to 
be more generic. I love that nim supports this! I may rework it and submit it 
as a module since it's so useful.


Re: Can I access arrays faster than this?

2019-03-05 Thread ggibson
That's a neat trick! Thanks for mentioning it. I'll have to learn about how the 
non-`.nim` files all actually work as I've been avoiding them.


Re: Can I access arrays faster than this?

2019-03-04 Thread ggibson
Hats off to you, sir. Thank you for pointing that out. I was under the 
impression opt:speed was default - nope.


Re: Can I access arrays faster than this?

2019-03-04 Thread ggibson
ookay, I think it was a memory fragmentation error, so probably it would have 
gone away if you had rebooted. I restructured the example to grab heap memory 
instead. Should work now!


Re: Can I access arrays faster than this?

2019-03-04 Thread ggibson
That's pretty weird! It works for me Clang v5 and GCC 6.4 on 64-bit CentOS 7.


Can I access arrays faster than this?

2019-03-04 Thread ggibson
I've been looking at array access and noticed that C++ seems to yield code that 
is 20x-30x faster for array access.


## compiled with: nim -d:r c filename
when isMainModule:
  const N = 20_000_000;
  var data {.noinit.}: array[N,int]
  # custom init
  for i in 0 ..< N:
data[i] = i
  # busy work
  for r in 1 .. 50:
for i in 3 ..< N-1:
  data[i] = (data[i+1]-data[i])+data[i-1]
  echo "result: ",data[N-2]


Run


// compiled with: c++ -O3 -o filename filename.cpp
#include 
int main()
{
  const int N = 2000;
  long long data[N];
  // custom init
  for (long long i=0; i

Re: Any easy ref iteration over immutables?

2019-03-04 Thread ggibson
@Araq Oops, missed your post. Okay, I'll be very interested in this "cursor" 
detection. I'll point people to the indexed loop in these cases for now.


Re: Any easy ref iteration over immutables?

2019-03-04 Thread ggibson
This gets me close, but I lack a way to say Hey nim, cast to a read-only 
reference


iterator refitems[T](a:openarray[T]):var T {.inline.} =
  ## iterates over each item of `a` so that you can ~~modify the yielded 
value~~ get a reference to the yielded value
  var i = 0
  while i < len(a):
yield cast[var T](a[i].unsafeAddr)
inc(i)


Run


Re: Any easy ref iteration over immutables?

2019-03-04 Thread ggibson
New test, still has full copy of items for iteration. 


## performs full copy in iteration of immutable
proc iterate_over(a:openarray[int]) =
  for c in a:
echo c
when isMainModule:
  let data = newSeq[int](10)
  iterate_over(data)


Run

C Source of `iterate_over()` with copy (`c = a[i];`): 


N_LIB_PRIVATE N_NIMCALL(void, iterate_over_9cD7bqNN5ugFAFo1Y0BNo9cw)(NI* a, 
NI aLen_0) {
nimfr_("iterate_over", "trial.nim");
{
NI c;
NI i;
c = (NI)0;
//  var i = 0
nimln_(2247, "system.nim");
i = ((NI) 0);
{
//  while i < len(a):
nimln_(2248, "system.nim");
while (1) {
tyArray_nHXaesL0DJZHyVS07ARPRA T4_;
NI TM_dkUgyuXqTi3PT7xs72dvsA_3;
//  while i < len(a):
//  while i < len(a):
if (!(i < aLen_0)) goto LA3;
//yield a[i]
nimln_(2249, "system.nim");
if ((NU)(i) >= (NU)(aLen_0)) 
raiseIndexError();
c = a[i];
//echo c
nimln_(3, "trial.nim");
nimZeroMem((void*)T4_, 
sizeof(tyArray_nHXaesL0DJZHyVS07ARPRA));
//echo c
T4_[0] = nimIntToStr(c);
echoBinSafe(T4_, 1);
//inc(i)
nimln_(2250, "system.nim");
TM_dkUgyuXqTi3PT7xs72dvsA_3 = addInt(i, 
((NI) 1));
i = (NI)(TM_dkUgyuXqTi3PT7xs72dvsA_3);
} LA3: ;
}
}
popFrame();
}


Run

The ref copy version: 


## Performs ref copy in iteration of mutable
proc iterate_over(a:var openarray[int]) =
  for c in a.mitems:
echo c
when isMainModule:
  var data = newSeq[int](10)
  iterate_over(data)


Run

Relevant section of generated C code: 


// 
c = ([i]);
// 


Run


Re: Any easy ref iteration over immutables?

2019-03-04 Thread ggibson
@Stefan_Salewski Good point about main vs global! I'd forgotten about that - 
unfortunately it doesn't change the result.

@mratsim Looking at the generated c code, it seems openarray iteration is 
indeed done with copy, even when an array of 1 billion elements 
(@Stefan_Salewski).

I'm not picking on nim here, rather I'm getting ready to teach a class on nim 
this summer at my university to some grad students and professors. I know some 
of the people who will be there and that they will ask about efficiency from a 
c++ perspective. I'll take your suggestion and try some actual data - will 
report back.

I've been following the work on move semantics - looking forward to it!


Any easy ref iteration over immutables?

2019-03-04 Thread ggibson
There's no way to do the following, easily, is there? (Yes, I can always 
cast/unsafeAddr, etc.)


# Easy & efficient mutable iteration (no unnecessary copying)
proc iterate_over(a:var openarray[int]) =
  for c in a.mitems:
echo cast[int](c.unsafeAddr)
break

var data = [1,3,5]
echo cast[int](data.addr)
iterate_over(data)


Run

output shows same memory addresses (as expected) 


94580668782512
94580668782512


Run


# Easy & inefficient immutable iteration (unnecessary copying)
proc iterate_over(a:openarray[int]) =
  for c in a:
echo cast[int](c.unsafeAddr)
break

var data = [1,3,5]
echo cast[int](data.addr)
iterate_over(data)


Run

output shows different memory addresses (as expected, but can we avoid this 
while still having immutable w/o ugly syntax?...) 


93899394672560
140734195148608


Run

Hard but efficient immutable iteration (no unnecessary copying) 


proc iterate_over(a:openarray[int]) =
  for c in cast[var array[3,int]](a.unsafeAddr).mitems:
echo cast[int](c.unsafeAddr)
break

var data = [1,3,5]
echo cast[int](data.addr)
iterate_over(data)


Run

output shows same memory addresses 


94865883576240
94865883576240


Run


Re: Convincing my friend about Nim

2019-01-01 Thread ggibson
Oh funny, one reason I was attracted to Nim was because it _was_ immediately 
readable to me, that its focus was about readability and representation. This, 
compared to rust, for example, which makes me start clenching my teeth. If a 
language goes down that rabbit hole, then it should just be like APL and 
actually be a new language with new symbols and everything so as to remain 
concise. /rant Okay, so what does that mean about your friend? Well, sounds 
like they just haven't used many languages, so they don't have the experience 
to really judge.


Re: Convincing my friend about Nim

2018-12-31 Thread ggibson
I need a work break so this is a bit long :p If your friend isn't just having 
fun with you, then I wouldn't try explaining it, but focus on accepting the 
difference to stay friends. This squabble happens a lot in the young tech 
crowd, but really any young crowd. Your friend is adopting what sounds like the 
attitude of someone who is afraid and doesn't yet know how to deal with it. 
That might sound strong, but most things we do are guided by fear or other 
primal emotions. Guessing they are in secondary school or early university, it 
may take them another 5-10 years (that's being generous) to develop the 
personal awareness and introspection to ask themselves why they are having this 
reaction. Only then could you have a reasonable conversation with them. Some 
possible reasons for that fear may be your friend is afraid to branch out from 
C#, because learning [all of] C# is such a monumental task they couldn't 
imagine doing more (it is a bloated language after all). Or perhaps they are 
afraid you will learn stuff they won't know and they like to have an upper hand 
with you. Or maybe they're afraid all their effort in learning C# is wasted 
(it's not) if there's actually other newer cooler languages they "should've" 
been focusing on. There are many possibilities, but I would bet they are afraid 
of something. Cheers.


Re: How-to silent the message "Jester is making jokes at..."

2018-12-09 Thread ggibson
Hmm, how might my attempt at this go wrong? I have 
`logging.setLogFilter(lvlNotice)` at the top after `import logging` but still 
jester is showing INFO level logging. I can make other changes and they show up 
okay.


Re: Help understanding UFC and templates

2018-12-09 Thread ggibson
Awesome! I saw this while mobile and forgot to reply, but this is exactly the 
kind of logical reason I was looking for. Thank you!


Help understanding UFC and templates

2018-12-07 Thread ggibson
Hi,

I still get tripped up by this. Why is it that some templates allow me to write 
using dot notation, and others do not? Is it that the ones that do not allow 
dot notation have untyped parameters? - Why would that affect it? My current 
workflow is to memorize the list of UFCable templates by trial and error, which 
is annoying. I'm hoping to find a better answer for when introducing nim to 
others.


import sequtils, tables
var a = {0:10,1:20,2:30}.toTable()
withValue(a, 1, value) do: # OK function call use of template
value[] = 11
a.withValue(1, value) do: # OK method call use of template
value[] = 11
echo toSeq(a.pairs) # OK function call use of template
echo a.pairs.toSeq() # ERROR method call use of template
# maybe the dot notation with iterator is confusing the compiler...
echo pairs(a).toSeq() # ERROR nope, still doesn't work


Run

Thanks!


Re: Workflow: how do I make a cpp lib in nim?

2018-09-18 Thread ggibson
@jyapayne Thank you for detailing all that! I had been using 0.18.0 because I'm 
on Win and that was the version available to download in zipped binary format. 
But apparently this requires new fixes in latest devel, as 0.18.1 worked nicely.


Re: Workflow: how do I make a cpp lib in nim?

2018-09-18 Thread ggibson
@jyapayne I think "can easily extend the example to c++" is giving me too much 
credit as I don't often deal with FFI scenarios. Does anyone have an example 
where this has been done? Either wrapping a nim->c library in c++, or wrapping 
a nim->c++ library in c++?


Re: Workflow: how do I make a cpp lib in nim?

2018-09-17 Thread ggibson
@sflennik Good suggestion. I did try that but it didn't work.


Re: Workflow: how do I make a cpp lib in nim?

2018-09-17 Thread ggibson
Still can't get this working. I even tried having nim export C code, and in the 
c++ code using `extern "C" int fib(int)` to no avail.


Re: Workflow: how do I make a cpp lib in nim?

2018-09-17 Thread ggibson
Progress! Thanks @jyapayne, the exportc pragma made the header look correct 
now. However, I still get the same error. If I try to make a C library instead, 
and compile a C-only program, then everything works as advertised. I didn't 
find an exportcpp pragma so I'm still stuck trying to do this for c++.


Workflow: how do I make a cpp lib in nim?

2018-09-17 Thread ggibson
Hi, I've been looking for a couple days and can't find out exactly how this is 
done. Goal: have cpp/h files generated that I can compile in with my c++ 
project to include helper functions originally written in nim. I'll try 
updating to development later to see if that fixes it.

What I'm doing: 


$ nim cpp -c -d:release --header --noMain mylib.nim (see below for src)
$ cd nimcache
$ ls
main.cpp (see below for src)
mylib.cpp
mylib.h

$ g++ -o main *.cpp -I/Nim-0.18.0/lib -w
stdlib_dynlib.cpp: In function 'void* 
symAddr_NHfjIU1Uh0ju9azgMjiSkQA(void*, NCSTRING)':
stdlib_dynlib.cpp:45:25: error: invalid conversion from 'FARPROC' {aka 
'long long int (*)()'} to 'void*' [-fpermissive]
  result = GetProcAddress(LOC1.dest, name);
$ gcc --version
<...> 8.2.0


Run


// main.cpp
#include 
#include "mylib.h"
using namespace std; // for demo

extern char** parseCSVListLine(const char*); // Seem to need this because 
mylib.h does not have it (?!)

int main() {
  parseCSVListLine("one,two,three");
  return(0);
}


Run


import strutils, sequtils, os, parsecsv, streams, future

proc parseCSVListLine*(str: string):seq[string] =
  var ss = newStringStream(str)
  var p: CsvParser
  p.open(ss, "parseCSVListLine()")
  discard p.readRow()
  return lc[ col.strip() | (col <- items(p.row)), string]

proc parseCSVListLine*(str: cstring):cstringArray {.extern: 
"parseCSVListLine".} =
  return alloccstringArray(parseCSVListLine($str))


Run


Re: Sequtil Question

2018-09-07 Thread ggibson
the `lc` needs to be converted to an openArray before filterIt gets it. I was 
trying `toSeq` or `items` neither of which worked, but `cycle(1)` does the 
trick. It's probably a bug; `lc` seems to need work judging by the issues list 
for it. FYI `future` is being renamed to `sugar` on devel.


(lc[i | (i<-0..9), int]).cycle(1).filterIt(it < 3).echo;


Run


Re: Best way to teach `..` vs `..<`?

2018-08-14 Thread ggibson
@mratsim is right - I finally found the original issue: 
[https://github.com/nim-lang/Nim/issues/6215](https://github.com/nim-lang/Nim/issues/6215)


Best way to teach `..` vs `..<`?

2018-08-14 Thread ggibson
My colleague recently stumbled on trying

> var x: array[1..<5, int]

which can only be done, I think, as

> var x: array[1..4, int]

What's the best way to teach why that doesn't work?


Re: nim vs c++ Why does nim show special chars in txt?

2018-03-31 Thread ggibson
Thanks!


nim vs c++ Why does nim show special chars in txt?

2018-03-31 Thread ggibson
I'm reading in a text file from Project Gutenberg (War and Peace) and the first 
line contains the following when I print it out using nim: "The Project 
Gutenberg EBook" Whereas in C++ doing the same thing I see no such special 
characters (the first 3). Nor in Notepad++ with all whitespace made visible. 
Help? Where are these characters coming from?


for line in lines "wap.txt":
echo line



Re: How to use declared() on properties, or concepts on types?

2017-09-16 Thread ggibson
Great explanations and details, thank you! Looks like it's time to read the 
manual again...


Re: Cygwin almost perfect... Nimble pathing help

2017-09-14 Thread ggibson
"solved"

Here's my hack, but it would be great to have a good way to specify that you're 
in a posix-like environment for pathing despite being on windows, and to use 
the cygpath utility as needed.

I modified the source of nimble (src/nimblepkg/download.nim) in the doClone() 
function I modified/added lines to the effect of:


let res = doCmdEx("cygpath " & downloadDir)
let fixedPath = string(res.output).strip()
doCmd("git clone --recursive " & depthArg & branchArg & url & " " & 
fixedPath)



Cygwin almost perfect... Nimble pathing help

2017-09-14 Thread ggibson
Hi there,

I finally got my cygwin+mingw32 environment to build nim. Everything works 
nicely except nimble barfs when trying to install anything. Is there a way I 
can tell it exactly what path to use or force nimble to use *nix pathing? 
Programs I write with nim work with *nix style paths on my system just fine.


$ nimble install nimcl
... 
... Output: Cloning into 
'C:\cygwin64\tmp\nimble_4860\githubcom_unicreditnimcl'...
... fatal: Invalid path 
'/cygdrive/c/Users/me/C:\cygwin64\tmp\nimble_4860\githubcom_unicreditnimcl': No 
such file or directory



$ nimble install nimcl --nimbleDir:/cygdrive/c/Users/me --verbose
Error: unhandled exception: The system cannot find the path specified.
 [OSError]



Re: infix op using a word as ident?

2017-03-14 Thread ggibson
Okay, thanks for clearing that up.


infix op using a word as ident?

2017-03-14 Thread ggibson
It's easy to make a new infix operator based on symbols like !*, and it's easy 
to redefine infix operators that use words like as, but how can I make a new 
infix operator with a word as the identifier, such as through?


## This doesn't work as infix, unless
## I call it like a standard proc
proc `through`(a,b:int) =
   echo "got $1 through $2" % [a,b]

`through`(3,4) ## works
3 through 4 ## fails



Making a tuple of procvars is weird

2017-03-12 Thread ggibson
Why does the first example below not work?


## First example
type ProcSimple = proc(x:int)
proc doSimple(x:int) {.procvar.} =
   echo "ran ok"

var b:tuple[a:ProcSimple,b:ProcSimple]
b = (a:doSimple,b:doSimple) ## Error: Mismatch
b.a(0)


The following is my workaround, by wrapping a procvar in a variable which is 
then used to create the tuple. 


## Second example
type ProcSimple = proc(x:int)
proc doSimple(x:int) {.procvar.} =
   echo "ran ok"

var b:tuple[a:ProcSimple,b:ProcSimple]
var procRef:ProcSimple = doSimple ## this seems silly
b = (a:procRef,b:procRef)
b.a(0)



Composition: how to track sub-type objects?

2017-03-10 Thread ggibson
I've been trying to figure out how to track a heterogeneous group of types 
while using composition. What is the recommended nimic way? Do I need some 
basic level of inheritance to accomplish this? See 
[wikipedia/composite_pattern](https://en.wikipedia.org/wiki/Composite_pattern) 
In OOP I would just use a seq[BaseClass] which is straightforward in nim.

Below is my attempt at this without using inheritance. I don't know what this 
method of programming is called without inspecting the generated C code, but I 
suspect that it's actually inheritance under the hood. It also looks like it'll 
become rife with massive switch statements for all shared procs.


type CarMake {.pure.} = enum Tesla,Mercury
type Car = ref object
   age:int
   case typ:CarMake:
  of CarMake.Mercury:
 leather:bool
  of CarMake.Tesla:
 summons_mode:bool
proc newMercury(has_leather:bool):Car =
   result = Car(typ:CarMake.Mercury, leather:has_leather)
proc newTesla(default_summons_mode:bool):Car =
   result = Car(typ:CarMake.Tesla, summons_mode:defaultSummonsMode)

proc decay(car:Car) = inc car.age

proc summon(car:Car) =
   stdout.write "Summoning your car... "
   case car.typ:
  of CarMake.Tesla:
 car.summons_mode = true
 echo "it might arrive."
  of CarMake.Mercury:
 echo "(calling home) They said 'No, get it yourself.' :("

var cars = newSeq[Car]()
cars.add( newMercury(hasLeather=true) )
cars.add( newTesla(defaultSummonsMode=false) )
for each_car in cars:
   each_car.summon




Re: Cannot import a file that has importcpp? Codegen issue?

2017-03-07 Thread ggibson
Resolved. I didn't not understand when to use importc vs importcpp. Apparently 
importcpp is ONLY for methods of classes. If I change my pragma to importc then 
everything is fine.


-From docs/backends.html-
"The importc pragma is the generic way of making backend
symbols available in Nim. The C++ or Objective-C backends
have their respective ImportCpp and ImportObjC pragmas
to call methods from classes."



Cannot import a file that has importcpp? Codegen issue?

2017-03-07 Thread ggibson
Hi, this looks like a codegen issue, but wanted to ask as I might be missing 
something simple. The code will only run if the type declaration is removed 
from the first file.

Tested on:

  * 0.16.1 (devel)
  * 0.16.0 (master)



File1: importme.nim 


## Random Device from C++
type TRandomDevice*
{.importcpp:"std::random_device", header:"".} = object
proc dothis*() =
   echo "ran the 'dothis' fn"


File2: main.nim 


import importme
dothis()


Clang Linker Error 


Undefined symbols for architecture x86_64:  
│~
  "_dothis_A9crgxPxoHyUlNFt9aA8PinQ", referenced from:  
│~
  _NimMainModule in testseq.o   
│~
ld: symbol(s) not found for architecture x86_64



Re: How is my mitems iterator wrong?

2017-03-05 Thread ggibson
Well that answers that. Thanks @Araq, and thanks for describing how you found 
the posted issue. This saves me more time with a brick wall.


How is my mitems iterator wrong?

2017-03-05 Thread ggibson
I'm practicing wrapping std::vector before attempting trickier things. I have 
the items iterator working, but the compiler complains I need an initializer 
when using mitems. All I can figure is that I'm missing wrapping some 
std::vector function related to initialization. I'd be grateful if someone 
could explain what's going on here.


{.pragma:vecheader, header:"".}
type vector {.importcpp:"std::vector", vecheader.}[T] = object
proc newVector[T]():vector[T] {.importcpp:"std::vector<'*0>()", vecheader.}
proc newVector[T](size:int):vector[T] {.importcpp:"std::vector<'*0>(#)", 
vecheader.}
proc newVector[T](size:int, val:T):vector[T] 
{.importcpp:"std::vector<'*0>(@)", vecheader.}
proc `[]`[T](base:var vector[T], idx:int):var T {.importcpp:"#[#]", 
vecheader.}
proc `[]=`[T](base:var vector[T], idx:int, val:T) {.importcpp:"#[#]=#", 
vecheader.}
proc push_back[T](base:var vector[T], val:T){.importcpp:"#.push_back(@)", 
vecheader.}
proc size[T](base:vector[T]):int {.importcpp:"#.size()", vecheader.}
iterator items[T](v:var vector[T]): T =
   for i in 0..