Re: Comparisons of Nim to the Chapel computer programming language...

2020-06-18 Thread Brad
Hi @mratsim —

I may have been unclear in my last response: I didn't mean to imply that I 
didn't believe there are realistic workloads that would result in recursive 
tasks or benefit from task serialization/squashing/stealing techniques. Just 
that the computations and users that have found their way to Chapel typically 
haven't exercised that style, so it hasn't been an area of focus for our team 
(combined with our choice to make Chapel tasks more arbitrary/unpredictable 
than most task-based programming systems).

Also, I should note that it's still possible to write recursive or dynamically 
balanced tasking programs in Chapel, simply that we typically express those 
patterns within the language or library rather than the implementation. For 
example, our libraries have iterators that can dynamically distribute 
iterations either locally across a compute node's cores or globally across 
multiple compute nodes and their cores. As another example, if I rewrite my 
naive Fibonacci computation in a way that manually throttles the creation of 
tasks rather than naively creating exponentially many of them, I can reduce the 
fib(40) case to just over a second on my 4-core laptop (I'll include my fib 
codes at the bottom of this for reference).

My colleage pointed out something from your earlier post that I didn't pick up 
on (and I imagine other readers may not have either): the Nemesis and Sherwood 
lines in the graphs you showed above are scheduler options in the Sandia 
Qthreads library that Chapel targets by default, so are representative of 
what's possible in Chapel today. Qthreads defaults to using the Sherwood 
scheduler, but Chapel chooses to use the Nemesis scheduler by default instead 
(though the user can override this default). We found that while the Sherwood 
scheduler was highly tuned for UTS (Unbalanced Tree Search) and great for 
highly unbalanced workloads with many many tasks, it had too much overhead for 
well-balanced operations, which is what we tend to care most about. In 
contrast, the Nemesis scheduler avoids those overheads and has much better 
performance for balanced workloads, but gives up work-stealing.

Ultimately we hope to have the best of both worlds. We had started some work 
with the Qthreads team to create a distrib scheduler that would do that 
([https://github.com/Qthreads/qthreads/issues/39](https://github.com/Qthreads/qthreads/issues/39)
 ), but the effort is currently stalled out.

Wrapping up, here's my naive Fibonacci in Chapel:


config const n = 10;

writeln("fib(",n,") = ", fib(n));

proc fib(n): int {
  if n < 2 then
return n;
  else {
var i, j: int;
sync {
  begin with (ref i) i = fib(n-1);
  j = fib(n-2);
}
return i+j;
  }
}

Here's my manually throttled version:


config const n = 10;

writeln("fib(",n,") = ", fib(n));

proc fib(n): int {
  if n < 2 then
return n;
  else {
if (here.runningTasks() >= here.numPUs()) then
  return fib(n-1) + fib(n-2);
else {
  var i, j: int;
  sync {
begin with (ref i) i = fib(n-1);
j = fib(n-2);
  }
  return i+j;
}
  }
}

And here's a very simple example of the bounded buffer pattern I was 
mentioning. We've never really treated this as a benchmark, more of a 
demonstration of how easy task parallelism can be in Chapel, where the key 
points are (a) task creation is simple and (b) sync variables avoid the need to 
worry about the typical overflow/underflow conditions:


config const buffsize = 10,
 n = 101;

var A: [0..#n] sync int;

cobegin {
  producer();
  consumer();
}

proc producer() {
  for i in 0..#n do  // write n values to the buffer
A[i%buffsize] = i;
  A[n%buffsize] = -1;   // write a "done" sentinel
}

proc consumer() {
  var pos = 0;
  do {
const val = A[pos]; // read value
if val != -1 then
  writeln("got: ", val);

pos += 1;   // advance cursor
pos %= buffsize;
  } while (val != -1);
}

A more full-blown version of this pattern that we use as an exercise for 
students in hands-on exercises (where their goal is to add support for multiple 
producers and consumers on the same buffer) can be found here (with sample 
solutions in the subdirectory): 
[https://github.com/chapel-lang/chapel/tree/master/test/exercises/boundedBuffer](https://github.com/chapel-lang/chapel/tree/master/test/exercises/boundedBuffer)


Re: Unclear (for Python people) import behavior. And how to deal with it

2020-06-18 Thread ZadaZorg
@juancarlospaco thanks, I read links you provide before. Maybe I'm skipped, but 
there were no explanations of such catch.

@Yardanico oh, thanks a lot. I think that is it!


Has anyone wrapped zlib or reimplemented deflate?

2020-06-18 Thread snej
To implement the network protocol I'm working on, I need to compress/decompress 
data using the [deflate](https://en.wikipedia.org/wiki/DEFLATE) algorithm. The 
existing C++ protocol implementation uses zlib for this.

I don't see any zlib wrappers or reimplementations in nimble, but thought I'd 
ask here, to see if anyone has done this already but not published it 
separately as a package. Otherwise I'll start building my own zlib wrapper, and 
eventually publish it to nimble.


Re: Unclear (for Python people) import behavior. And how to deal with it

2020-06-18 Thread juancarlospaco
  * 
[imports](https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programmers#Imports)
  * 
[Objects](https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programmers#Objects)
  * [I recommend read it 
completely](https://github.com/nim-lang/Nim/wiki/Nim-for-Python-Programmers#table-of-contents)




Re: Unclear (for Python people) import behavior. And how to deal with it

2020-06-18 Thread Yardanico
Your example can be fixed by doing 


export ex.uuid


Run

Or, if you want to export _everything_ from that module (export only exports 
things which are marked by `*`: 


import ex
export ex


Run

See 
[https://nim-lang.org/docs/manual.html#modules-export-statement](https://nim-lang.org/docs/manual.html#modules-export-statement)


Re: Has anyone wrapped zlib or reimplemented deflate?

2020-06-18 Thread Yardanico
Check out [https://github.com/nim-lang/zip](https://github.com/nim-lang/zip)


Unclear (for Python people) import behavior. And how to deal with it

2020-06-18 Thread ZadaZorg
During my learning of nim, I'm trying to implement some kind of code common for 
Python OOP. I'm spent a lot of time reading articles, book, forum and feels 
like I'm more or less OK with basics.

But today I meet strange bug (as I initially think), which is explained in 3 
listings below...

File **ex.nim**


type Entity*[T] = ref object of RootObj
props*: T
id*: int
name*: string


proc uuid*[T](entity: Entity[T]): int =
echo "Running base class uuid ..."
entity.id


Run

File **ex2.nim**


import ex

type UserProps* = object
username*: string


type User* = ref object of Entity[UserProps]


Run

File **ex3.nim**


import ex2
# import ex

let up = UserProps(username: "Telega")

let u = User(props: up, id:8)

# src/ex3.nim(8, 7) Error: undeclared field: 'uuid' for type ex2.User 
[declared in src/ex2.nim(7, 6)]
echo u.uuid


Run

If we try to compile `ex3.nim` it will fail with error `undeclared field: 
'uuid' for type ex2.User`. When code listed in the file `ex3.nim` was in 
`ex2.nim` all works OK. When I move code to the new file, there is an error.

Then I realize, that importing import ex fixes the error. But I was surprised 
by this.

And only then I realize, that `u.uuid` is actually `uuid(u)` and this procedure 
was not imported.

So, that is not a history about my smartness :)

My questions are:

  * What is a nim way to write such code? (I'm thinking about `include`, but 
not sure, this is the true way.)
  * In other words, how should I notify users of my code, that they have to 
import additional modules?
  * How to explain this approach/behavior to Python people? (I'm already 
explained this to myself, but I do not know how to live with this knowledge 
comfortably)



I'm pretty sure, that trying to reflect what I was doing in Python for many 
years is not follow nim-way, but that is my learning curve, so any links to 
good examples or explanations are welcome, coz I saw a lot of examples of a 
library-, utility-, framework- related code, but almost no examples of boring, 
enterprise-related stuff.

Thanks.


Re: Visual Studio Code plugin

2020-06-18 Thread lscrd
Yes, you are right. But as Nim syntax doesn’t change a lot, this is 
understandable. Nevertheless, there are several issues which should have been 
solved (easier said than done of course).

The alternative plugin seems currently more active. So, this may be a better 
choice in the future. But I think that most current users of the original 
plugin do not even know that an alternative now exists. And, most are satisfied 
with the original plugin despite some issues. 


Re: Visual Studio Code plugin

2020-06-18 Thread ZadaZorg
I just choose to use Nim-alt, and did not meet with any problems. Everything I 
expect is work, but I'm not a very powerful user of Nim yet.


Re: Parallel coding in Nim (as compared to OpenMP/MPI)

2020-06-18 Thread hugogranstrom
I can try to answer 5), that's really the only one I'm qualified to answer XD 
I'm also learning Weave now and it's a really nice experience and your other 
questions intrigues me as well.

The difference between addr and unsafeAddr is that addr only works on mutable 
things like var output for example. But it doesn't work on immutable things 
like let input. I guess this is to make sure that we consciously have to make 
the decision to use the unsafe variant if we want to change something that we 
have declared to be unchangeable. Hope this helped clear it up a bit :)


Re: Nim version 1.2.2 is out!

2020-06-18 Thread LeFF
That's great, thank you! 


Re: Nim version 1.2.2 is out!

2020-06-18 Thread snej
I just filed 
[https://github.com/nim-lang/Nim/issues/14719](https://github.com/nim-lang/Nim/issues/14719)
 to request this.


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread Yardanico
By "main config" I mean 
[https://github.com/nim-lang/Nim/blob/devel/config/nim.cfg](https://github.com/nim-lang/Nim/blob/devel/config/nim.cfg)


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread Yardanico
That's not a nimble bug - see 
[https://github.com/nim-lang/Nim/issues/14272](https://github.com/nim-lang/Nim/issues/14272)


Re: Parallel coding in Nim (as compared to OpenMP/MPI)

2020-06-18 Thread jasonfi
A link to an article I wrote: 
[https://onlinetechinfo.com/concurrency-and-parallelism-in-nim](https://onlinetechinfo.com/concurrency-and-parallelism-in-nim)
 (with lots of links).


Re: Comparisons of Nim to the Chapel computer programming language...

2020-06-18 Thread mratsim
> For example, a favorite toy Chapel program creates a fixed number of tasks 
> that compute a producer-consumer pattern on a bounded buffer of 
> synchronization variables with full/empty semantics. In my experience, this 
> is a challenging pattern to express in many task-based systems due to their 
> restricted task semantics. In this sense, our tasks might be considered to be 
> more like "threads", though we reserve that term for the system resources 
> used to execute the tasks.

Is there reference code and/or benchmark code I can use? I would be interested 
to add that to Weave benchmark suite and see how the runtime cope with this 
scenario. This would also help me to evaluate GCC OpenMP weaknesses if any for 
that type of workload.

> But frankly, (a) we haven't run into many (any?) practical code patterns from 
> users that would benefit greatly from such techniques and (b) we haven't 
> wanted to struggle with either trying to adapt those approaches to Chapel 
> semantics or with having the compiler distinguish between tasks that can be 
> cooperatively scheduled/serialized vs. those that can't. In saying this, my 
> intention isn't to throw that line of work under the bus, just to state that 
> it hasn't been a priority for the codes and users we've worked with, so it 
> remains on our list of rainy day projects. If a grad student was interested 
> in researching the application of cooperative task scheduling approaches to 
> Chapel while preserving our semantics, I'd be all for it.

One things that come to mind are tree algorithms.

1\. Monte-Carlo Tree Search, is the go-to algorithm for reinforcement learning 
and has been used to great effect since 2006 to build go engines. Robot 
competition winners with tasks like put many balls in a basket have also been 
using MCTS for a decade now.

While the media focused on the advanced of deep learning from Google Deepmind, 
the truth is that the deep learning engine is feeding the Monte Carlo Tree 
Search engine (though it can run without and still be strong, it will misplay a 
lot). Monte Carlo Tree Search is described here: 
[https://en.wikipedia.org/wiki/Monte_Carlo_tree_search](https://en.wikipedia.org/wiki/Monte_Carlo_tree_search)
 and is used to solve problems with imperfect information or a too large search 
space in an optimal way, including Poker. Those problems being called 
"Multi-Armed bandits" (as in the bandit slot machines).

This website [https://banditalgs.com](https://banditalgs.com)/ and the 
accompanying book 
[https://tor-lattimore.com/downloads/book/book.pdf](https://tor-lattimore.com/downloads/book/book.pdf)
 are an excellent resource

Parallelizing MCTS was a very active area of research at one point with 3 
different techniques being explored:

  * tree parallelism where threads duplicated the tree locally and there was 
some merging going on
  * leaf parallelism where threads where assigned a leaf of the (game/decision) 
tree to explore
  * branch parallelism



I'm of the mind that a good multithreading runtime would trivialize those 
concerns.

2\. Large clustering algorithms (kNN, DBSCAN, ...) are recursive as well with 
some clusters being quite compute intensive and others being empty which means 
that load balancing is critical.

3\. Raytracing is very compute intensive and as mentioned in my thread here: 
[https://forum.nim-lang.org/t/6367#39266](https://forum.nim-lang.org/t/6367#39266)
 it's also recursive with a random recursion depth (terminated by an algorithm 
aptly called the Russian Roulette).

>From this picture:

Clang/Intel OpenMP and Intel TBB have the load balancing at B, as they do 
"eager task splitting", while Weave does load balancing C with "lazy task 
splitting" the tasks being generated by 2 parallel for loop over the image 
bounds.

How to parallelize raytracing is a quite active area of research, especially on 
GPU that have poor to no support to recursive function calls with indeterminate 
recursion depth.

4\. Beam Search: for voice recognition and image captioning, neural networks 
often have to explore and backtrack between multiple candidates, backtracking 
imposes quite a lot of constraint on a load balancer.


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread snej
> Are you putting -d:release in the config file by any chance? If you do - that 
> wouldn't work, you must specify it in the call to the compiler/nimble build

That's it! I put it in `nim.cfg` like all the other compile options. If instead 
I run `nimble build -d:release`, I get an optimized build.

The help text for `nimble` doesn't describe the options to `build`, it just 
says `[opts, ...] [bin]`. And I already knew I could put `nim c` option flags 
in the config file, so it seemed obvious to put `-d:release` there.

Help me understand the build process better -- why is it different putting it 
on the command line vs. in the config file?


Re: Parallel coding in Nim (as compared to OpenMP/MPI)

2020-06-18 Thread Rooibos
Thanks very much for detailed info and various links! I did not even know that 
OpenMP is supported via `||` (though with some restriction), so I will play 
around with it and also learn Weave (which seems more flexible and efficient).

And, I have several more questions...

1) Based on the above info, there are (roughly speaking) three different 
parallel approaches in Nim; is this understanding correct...?

  * OpenMP (via `||`)
  * Weave
  * Threads, channels, etc, as described in the Nim manual and "Nim in Action", 
Chap.6 (and also experimental parallel statement: 
[https://nim-lang.org/docs/manual_experimental.html#parallel-amp-spawn-parallel-statement](https://nim-lang.org/docs/manual_experimental.html#parallel-amp-spawn-parallel-statement))



2) In both OpenMP and Weave, is it essential to first cast `seq` to 
`UncheckedArray` and use the latter in a parallel region (e.g., inside for-loop 
with `||`, or a block within `init(Weave)` ... `exit(Weave)`)? In that case, is 
it also possible to cast `Tensor` (in Arraymancer) to `UncheckedArray` by 
getting a raw (unsafe) data pointer somehow?

3) In the example code of Weave for matrix transpose, `captures` are used for 
some variables:


parallelFor j in 0 ..< N:
captures: {M, N, bufIn, bufOut}
parallelFor i in 0 ..< M:
  captures: {j, M, N, bufIn, bufOut}


Run

Here, is the meaning of `captures` similar to `shared` in OpenMP (roughly 
speaking)...?

4) I have installed Weave-0.4.0 (+ Nim-1.2.2) and tried the matrix transpose 
code shown in the Github page. Here, I also added the below code at the end of 
main() to print some array elements:


# In proc main():
  ...
  init(Weave)
  transpose(M, N, bufIn, bufOut)
  exit(Weave)
  
  # Show some elements.
  echo("input  [2 * N + 5] = ", input[2 * N + 5], " (= ", bufIn[2 * N + 5], 
")")
  echo("input  [5 * N + 2] = ", input[5 * N + 2], " (= ", bufIn[5 * N + 2], 
")")
  echo()
  echo("output [2 * M + 5] = ", output[2 * M + 5], " (= ", bufOut[2 * M + 
5], ")")
  echo("output [5 * M + 2] = ", output[5 * M + 2], " (= ", bufOut[5 * M + 
2], ")")


Run

Compiling as `nim c --threads:on test.nim` gives the expected result:


input  [2 * N + 5] = 4005.0 (= 4005.0)
input  [5 * N + 2] = 10002.0 (= 10002.0)

output [2 * M + 5] = 10002.0 (= 10002.0)
output [5 * M + 2] = 4005.0 (= 4005.0)


Run

On the other hand, if I moved `exit(Weave)` after all the above `echo` 
statements, the result changes to 


input  [2 * N + 5] = 4005.0 (= 4005.0)
input  [5 * N + 2] = 10002.0 (= 10002.0)

output [2 * M + 5] = 0.0 (= 0.0)
output [5 * M + 2] = 0.0 (= 0.0)


Run

Does this mean that `exit(Weave)` has the role of some "synchronization"(?) for 
parallel calculations, and so mandatory before accessing any `UncheckedArray` 
used in the `parallelFor` regions?

5) Again, in the matrix transpose code above, the `input` (of type `seq`) is 
cast to `bufIn` (of type `UncheckedArray`) by using the address obtained from 
`input[0].unsafeAddr`. On the other hand, `.addr` is used to cast `output` to 
`bufOut`. Is this difference important, or is it actually OK whichever of 
`.unsafeAddr` or `.addr` is used?


let input = newSeq[float32](M * N)
let bufIn = cast[ptr UncheckedArray[float32]]( input[0].unsafeAddr )
...
var output = newSeq[float32](N * M)
let bufOut = cast[ptr UncheckedArray[float32]]( output[0].addr )


Run

I am sorry again for many questions! These are not urgent at all (I'm still 
learning more basic syntax...), but I would appreciate any hints and inputs 
again. Thanks very much :)

PS. "seems like you love tea ;)" Yes, I recently like to drink Rooibos tea 
(particularly at night), though I like coffee in the morning :)


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread Stefan_Salewski
> key distribution matters a lot

That is true, but it is obviously not the problem for Mr snej. He gets good 
performance when he disables all checks one by one, but not with -d:danger. So 
his configuration is somewhat broken.

And note, -d:danger is enough, no need for -d:danger -d:release. We should not 
confuse people too much. Same for -d:release --opt:speed, -d:release already 
includes --opt:speed.


Re: Hi all, pass Nim functions to C code as callbacks?

2020-06-18 Thread Stefan_Salewski
That is done in libs like gtk a lot. The Nim procs needs the cdecl pragma for 
this to work.


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread coffeepot
Just wanted to add to what @treeform mentioned, key distribution matters a lot 
when deleting with tables. Check out the timings of sequential keys vs a more 
distributed table access.


import tables, times, random, sugar

template bench(code: untyped) =
  let t1 = cpuTime()
  code
  let t2 = cpuTime()
  echo "Line ", instantiationInfo().line, " took ", t2 - t1

var t: Table[int, int]
const tests = 100_000

bench:
  for i in 0 ..< tests:
t.add i, 1

bench:
  for i in 0 ..< tests:
t.del i

let randomKeys = collect(newSeqOfCap(tests)):
  for i in 0 ..< tests:
rand int.high

bench:
  for i in 0 ..< tests:
t[randomKeys[i]] = 1

bench:
  for i in 0 ..< tests:
t.del randomKeys[i]


Run

I get the following output with -d:danger -d:release:

  * Line 12 took 0.003
  * Line 16 took 7.209
  * Line 24 took 0.00178
  * Line 28 took 0.003114



In this example, deleting with sequential keys is 2400 times slower than keys 
with a more random distribution.


Re: Perf: Table.del(key)is taking 85% of my code's time

2020-06-18 Thread Yardanico
Are you putting -d:release in the config file by any chance? If you do - that 
wouldn't work, you must specify it in the call to the compiler/nimble build


Re: Is --gc:arc completely independent from the older ownership model?

2020-06-18 Thread didlybom
Thank you @Araq, that is pretty clear. This matched what I would expect from a 
“deterministic” memory management model. I don’t take that to mean I know 
_[exactly](https://forum.nim-lang.org/postActivity.xml#exactly) when me left is 
freed but that you can reason about it (as opposed to a garbage collector that 
can run more or less at any time).

What kinds of optimizations are currently done by arc? Would it be fair to say 
that the baseline is that everything (other than value types) is handled more 
or less like a shared_ptr by default but that the compiler is able to do some 
optimizations, which would be equivalent to using a unique_ptr in C++ where it 
makes sense or even not using any kind of reference counting at all (at 
runtime)? That is, is it possible for the compiler to completely eliminate the 
cost of reference counting during compilation, achieving the same performance 
that you could achieve if you managed your memory manually? I guess that is 
what it would mean to do “compile time reference counting”.

Also, how does orc change the picture?


Re: Is --gc:arc completely independent from the older ownership model?

2020-06-18 Thread Araq
I think you should watch my talk at NimConf. 


Hi all, pass Nim functions to C code as callbacks?

2020-06-18 Thread hyvuminhtuan
Hello forum im a new, nice to meet u all.

I've looked around and I can't answer this. I want to be able to pass a Nim 
function / proc to C as a function pointer and get C to call it. I don't have a 
specific reason I want to do this, but I might need it soon.

Many tks


jester: one handler for several routes?

2020-06-18 Thread luntik2012
I'd like to write something like C's switch/case. Is it possible without 
writing a custom router?


routes:
  get "/hello":
  get "/helloWorld":
resp "Hello World"



Run

I can write separate handler proc and return http code, headers and content, 
but may be there is a more beautiful solution?


Re: Visual Studio Code plugin

2020-06-18 Thread didlybom
Thanks Iscrd. I am not saying that the old plugin is abandoned but it certainly 
seems to be updated much more slowly than nim itself.


Re: When will the NimConf timeline get posted?

2020-06-18 Thread Araq
We're scheduling the talks today and will contact the speakers and update the 
website afterwards. Sorry for the delay but just today we received 3 more 
talks. 


Re: When will the NimConf timeline get posted?

2020-06-18 Thread digitalcraftsman
There's a dedicated page for NimConf 
([https://conf.nim-lang.org)](https://conf.nim-lang.org\)), so I guessing it 
will be posted there at some point of time.


Re: Visual Studio Code plugin

2020-06-18 Thread lscrd
Personally, I use the original plugin as I was not aware that an alternative 
one exists. This plugin seems in fact quite recent (first commit by Gary M on 
20 April) and, logically, there is some activity on it.

Besides, we can’t say that the original plugin is abandoned as the last commit 
was on 26 March. And this plugin works with stable and development versions of 
Nim.

I have installed the alternative plugin to look at the differences. An issue 
with symbolic links I reported long time ago (for the original plugin) is also 
present in the alternative plugin, so we can’t expect all issues to be solved.

It seems that the main goal of this new plugin is to provide another style for 
syntax highlighting, while solving some syntactical bugs. I tried to compare 
the plugins and have not been convinced by this new style. But this is of 
course a question of taste.

For now, the original plugin is still maintained, even it there are old issues 
still not solved. Maybe this new plugin will be more actively maintained or 
maybe not. Only time will tell.

You can install both plugins and do some comparisons to find the one which best 
suits your taste. Activate only one at a time of course :-).


Re: When will the NimConf timeline get posted?

2020-06-18 Thread sschwarzer
Hm, it's clearly after Tuesday now and the conference is only two days away. It 
would be really nice to get a timetable of the talks. :-)


Re: Is --gc:arc completely independent from the older ownership model?

2020-06-18 Thread Araq
Well I can only describe how arc works and I can assure you that Rust/Lobster 
work very similarly and none of these languages have "compile-time reference 
counting", strictly speaking.

Nim's integers, floats, enums, bools and objects of these and arrays of these 
_always_ are "value" based types. And always have been. They are embedded into 
the host container. They are not necessarily allocated on the stack (though 
usually they are), for example:


type
  O = object
 a: array[2, int]

proc main =
  var x = (ref O)(a: [1, 2]) # aha! we have an array here! and it's not 
allocated on the stack!



Run

`a` is directly _embedded into_ the `O` and we put it onto the heap. The `x` 
itself is stored on the stack and it points into the heap. Now the question is: 
When is the block inside the heap freed? Under --gc:arc/orc it's always at the 
end of `main`. Under the other GCs it's "you don't know". That is true for C++ 
shared_ptr, unique_ptr, Rust's equivalents and whatever Lobster's name for 
these things is.

Why is that? Well there is one pointer to the `ref O`, it's a _uniquely_ 
referenced memory cell. Now let's make this program more complex:


proc main =
  var x = (ref O)(a: [1, 2])
  var y = x



Run

Now we have 2 references to `ref O`. When it is freed? Still at the end of 
`main`. Why? Because that's how reference counting works. What's the point of 
move semantics then? It makes the assignment `var y = x` cheaper by exploiting 
that `x` isn't used afterwards. Does this affect "deterministic" memory 
management? No.

Ok, so about this example:


proc construct(p: int): ref O =
  var x = (ref O)(a: [1, 2])
  if haltingProblem(p):
result = x
  else:
result = nil

proc main =
  let x = construct(12)


Run

When is the `ref O` object really freed? Well it depends on a halting problem, 
either it's freed right after `construct` or after `main`. Why is that? Because 
unique pointers are really a 1 bit reference counting system. Note how even 
uniqueness doesn't help all that much with "deterministic" memory management 
because the uniqueness means "0 or 1" and not "always 1". However, in practice, 
if you do a minimal amount of testing or reasoning about your code, the runtime 
profile of your code remains analysable. That's true for both classic reference 
counting like C++'s shared_ptr and Rust's 1-bit reference counting or various 
schemes in between where you optimize away more and more RC operations 
("compile-time reference counting").

So why is this "better" for "hard realtime" systems than classical tracing GC 
algorithms or copying GCs or Jamaica's hard realtime GC? It's better in the 
sense that it attaches a simpler _cost model_ to a program where some 
modularity is preserved. Your subsystem allocates N objects on the heap? The 
costs are N deallocations when the subsystem is done, regardless of other 
subsystems in your program.


Visual Studio Code plugin

2020-06-18 Thread didlybom
I see that there are 2 Visual Studio Code extensions for nim. The one that has 
the most downloads by far is vscode-Nin 
([https://github.com/pragmagic/vscode-nim)](https://github.com/pragmagic/vscode-nim\)).
 That one is not updated very frequently. I don’t think it even claims to 
support nim 1.0, let alone 1.2. In its documentation it still references VSCode 
0.10!

There is another one called Nim-alt 
([https://marketplace.visualstudio.com/items?itemName=garym.nim-alt](https://marketplace.visualstudio.com/items?itemName=garym.nim-alt))
 which seems to be a fork of the first one (perhaps due to the lack of activity 
in the first one?). It has been updated more recently and claims to have fixed 
some problems with the original extension. Which one do you guys recommend?

I know that editors and IDEs are very personal choices for a lot of people. Yet 
I think that I order for nim to become a more mainstream language there should 
be at least one good quality, up to date extension for at least one of the 
major editors. From what I’ve read in this forum VSCode seems to be the most 
commonly recommended nim programming environment. The fact that the available 
VSCode extensions seem to lag significantly behind the language does not look 
great.


Re: Is --gc:arc completely independent from the older ownership model?

2020-06-18 Thread didlybom
I have not followed the arc story too closely but I have a few questions about 
it. In particular I’d like to understand how it compares to the C++ memory 
model.

I skimmed the Lobster memory model document referenced by @Araq. In it they 
talk about “in-line, by-value structs”. Is this model used by arc for local, 
“simple” variables? That is, with arc, are Integers, floats, etc stored in the 
stack like they are in C++? What about strings and seqs? Are those immediately 
destroyed when the procedure in which they are declared exits? What about 
objects in general?

In another part of the Lobster memory management document they say:

Lobster combines its original (runtime) reference counting with a lifetime 
analysis algorithm, to get “compile time reference counting”.

Is this applicable to arc? If so, when do we get the compile time reference 
counting and when do we get the runtime reference counting?

Would it be correct to assume that arc would be equivalent to wrapping all 
variables of “non simple” types with std::shared_ptr in C++? Or perhaps with 
std::uniqur_ptr or a mix of both?

How deterministic is the memory management with arc? What about orc? Is there a 
garbage collector still needed and running in either case? Is there any runtime 
overhead due to the reference counting compared to what would be achieved with 
C++’s manual memory management?

Sorry if these questions have very obvious answers. I really think that some 
documentation comparing the arc (and the future orc?) memory model to the C++ 
model would be very useful that come from that kind of language.