Re: Help understanding simple string pointer indexing example
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
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
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
@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
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
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
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.
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.
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?
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
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?
Ah, okay. Thank you both for the clarification.
procs operating on concepts?
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
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?
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?
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?
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
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?
@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?
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?
> 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?
> * 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?
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?
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?
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?
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?
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?
@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?
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?
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?
@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?
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
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
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..."
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
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
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?
@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?
@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?
@sflennik Good suggestion. I did try that but it didn't work.
Re: Workflow: how do I make a cpp lib in nim?
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?
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?
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
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 `..<`?
@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 `..<`?
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?
Thanks!
nim vs c++ Why does nim show special chars in txt?
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?
Great explanations and details, thank you! Looks like it's time to read the manual again...
Re: Cygwin almost perfect... Nimble pathing help
"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
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?
Okay, thanks for clearing that up.
infix op using a word as ident?
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
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?
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?
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?
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?
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?
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..