Re: Procs that work only inplace like strutils.removeSuffix()

2019-08-05 Thread mratsim
That is something quite general and a decision in the end of library authors 
(including standard library).

In my case, I try to design a "low-level" API that works completely in-place, 
this has the side-benefits of allowing the return value to be an error code, nd 
also a high-level API that returns a new value (and uses exception).

The low-level is important because in scientific computing, allocating is often 
a bottleneck and you want to avoid it if you can. The high-level is because 
`let c = a + b` is much nicer than any in-place alternative that would require 
pre-allocation.

One approach that was really nice was Lua's which allow chaining of methods 
that had in-place results: 
[http://lua-users.org/wiki/MethodChainingWrapper](http://lua-users.org/wiki/MethodChainingWrapper)


Re: Compile time vs run time

2019-08-05 Thread williamholding
Compile time:

string my_value = Console.ReadLine(); int i = my_value;

A string value can't be assigned a variable of type int, so the compiler knows 
for sure at compile time that this code has a problem

Run time:

string my_value = Console.ReadLine(); int i = int.Parse(my_value);

Here the outcome depends on what string was returned by ReadLine(). Some values 
can be parsed to an int, others can't. This can only be determined at run time.

More on... 
[http://net-informations.com/python/iq/checking.htm](http://net-informations.com/python/iq/checking.htm)


Re: Trouble creating type containing generic array

2019-08-05 Thread mratsim
Check how the [stats standard library](https://nim-lang.org/docs/stats.html) is 
[implemented](https://github.com/nim-lang/Nim/blob/master/lib/pure/stats.nim#L56)
 or just reuse it.


Re: wNim - Nim's Windows GUI Framework

2019-08-05 Thread Ward
Print dialog is added as you wish, and more (page setup dialog, printer 
support, region and shaped window, high DPI support, etc).


Re: Trouble creating type containing generic array

2019-08-05 Thread jlhouchin
My apologies for not being more clear. I could easily simply create and pass 
around the plain seqs. But that defeats the purpose. The purpose is to maintain 
state and knowledge of the array or seq that a smarter object can do.

For example in time series data that I collect as time goes on or on historical 
data that I operate on as if I am in the moment.

It is far less expensive to maintain state of a seq than to perform operations 
on it. Especially if those operations are being done over and over.

I tried for a minimal example that would teach me what I needed to know to fix 
my understanding and solve my problem. However it is not a complete example.

An easy example is if I had a seq of which I wanted to know the sum, average, 
max and min.

All these things are easily achieved in a seq or array and computed when 
desired. They can also become expensive. What is the cost of sum, max and min 
over a arbitrarily large array? Verses the cost of maintaining a sum, max and 
min. And then you multiply that cost by every object which has a reference to 
that seq.

That is what I am trying to achieve. Nim is amazing. Its performance in those 
computation is outstanding. However, if I can avoid them in the first place. I 
can do better.

Creating such an object even in a dynamic language makes knowing the sum, max 
and min instant even over a multi-million valued array.

Then the question might be why have the array not simply maintain state. The 
array is part of the state. And I do not know that there are no other 
requirements which can only be met by the array itself.

Hope this helps.

Thanks for engaging in the conversation.


Re: Trouble creating type containing generic array

2019-08-05 Thread jlhouchin
Thanks. That works and got me going.

I wasn't trying to pass types as a string so much as knowledge about the type.

I am still working on understanding generics. I have not found much 
documentation regarding generics. I have the book and I have read the Tutorial 
II.

Most documentation is regarding defining a proc not a type.

Is there documentation I am overlooking? Or is there a good source of source 
code which would have good examples that are comprehensible by mortals. :)

Again thanks.


Re: What text editor are you using for Nim?

2019-08-05 Thread as1ndu
VSCode. There is a nice extension for Nim with debugging etc


Re: Procs that work only inplace like strutils.removeSuffix()

2019-08-05 Thread Stefan_Salewski
> is what you want?

Obviously not really -- strutils.removeSuffix() was only an example for some 
Nim procs which works only in place, while user may need a proc that returns a 
modified value. (English is not my native language, but after rereading my 
initial post, I think that my description was not too bad. But maybe I can 
write my next post more clearly :-)

But I think Araq has understood the core of my concern.


Re: Data loss with async sockets

2019-08-05 Thread pigmej
Few cents from my side

Seeing all that makes me kinda sad. Nim is pretty neat language and the 
ecosystem seems to be moving into the proper direction BUT situation like that 
especially just in sight of 1.0 is at least super concerning.

My experience with asyncdispatch is mostly positive BESIDES times where I've 
hit some corner cases / weird behaviour / undefined behaviour. Having something 
that is having a lot (let's be honest there...) corner cases, and kinda 
unexpected design decisions (.connect with UDP) is not super optimal I think, 
especially that the aim is 1.0. Not having cancellation is really hard block 
for me, I can't imagine having something running on production without being 
able to cancel the futures. It will basically screw up most of the error 
handling.

I'm not saying that asyncdispatch is wrong, it's okish, but it requires A LOT 
of extra testing and stabilization.

The community split between asyncdispatch and chronos (a hard fork of 
asyncdispatch) sounds very bad for me, especially that our community is rather 
small. In the same time, the existence of chronos proves that async is possible 
outside of stdlib which is great I think.

Seeing and having that situation is definitely not helping nim with adoption... 
is there any sight how that can be solved/mitigated?


Re: Procs that work only inplace like strutils.removeSuffix()

2019-08-05 Thread treeform
Maybe proc changeFileExt(filename, ext: string): string {...} ( 
[https://nim-lang.org/docs/os.html#changeFileExt%2Cstring%2Cstring](https://nim-lang.org/docs/os.html#changeFileExt%2Cstring%2Cstring)
 ) is what you want?


Re: Trouble creating type containing generic array

2019-08-05 Thread mratsim
I'm not too sure of your end goal but Nim is a static language so types must be 
known at runtime, you can't pass them a a string.

Also your type is generic over int or float so you need to use the generic 
syntax:


type
  MyArray*[T: int|float] = ref object
length*: int
index: int
arr: seq[T]

proc createMyArray[T: int|float](length: int, tp: typedesc[T]): MyArray[T] =
  result = MyArray[T](
length: length,
index: 0,
arr: newSeq[T](length)
  )

var ma = createMyArray(1000, float)


Run


Re: Trouble creating type containing generic array

2019-08-05 Thread treeform
Why are you trying to create such a thing?

I am sure you could make such thing in nim (you can do anything in nim). Buy 
why?

I think the reason its hard to do such a thing is that nim is trying to say 
don't do it this way.

If you know the type of array at compile time just use: 


var ma = newSeq[float](rows)


Run

If you don't, use a case object:


type
  OddArrayKind = enum
OddInt, OddFloat
  
  OddArray* = ref object
case kind: OddArrayKind
of OddInt:
  intSeq: seq[int]
of OddFloat:
  floatSeq: seq[float]


proc createMyArray(length: int, strSind: string): OddArray =
  if strSind == "int":
OddArray(kind: OddInt, intSeq: newSeq[int](length))
  else:
OddArray(kind: OddFloat, floatSeq: newSeq[float](length))


var rows = 23
var ma = createMyArray(rows, "float")


Run

I would strongly suggest creating the intSeq or the floatSeq and passing that 
around instead of doing case objects and these odd string types.


Re: Wow. It all 'just works'

2019-08-05 Thread Araq
Once more, this is hardly on topic and the wrong forum to discuss these things.


Trouble creating type containing generic array

2019-08-05 Thread jlhouchin
I am trying to create a type which is basically an Array with additional 
information. I want to use only [int | float] for the Array.


type
  MyArray* = ref object
length*: int
index: int
arr: seq[int|float]

proc createMyArray(length: int, tp: string): MyArray =
  if tp == "int":
let ttype = int
  elif tp == "float":
let ttype = float
  result = MyArray(
length: length,
index: 0,
arr: newSeq(ttype)[length]
  )

var ma = createMyArray(int(rows), "float")


Run

The code is probably naive as I am still learning. The MyArray type compiles if 
everything below is commented out. As soon as I uncomment, it gives me this 
error.


/home/jimmie/Dev/Nim/ntplayground.nim(125, 19) Error: invalid type: 'int or 
float' in this context: 'proc (length: int, tp: string): MyArray' for proc



Run

Any help, wisdom or understanding greatly appreciated. 


Re: What text editor are you using for Nim?

2019-08-05 Thread jlhouchin
I have been briefly exploring Kakoune. I like the idea of a less bloated 
editor. Currently I have been using Atom. I have not yet really gotten into 
Vim, or Emacs. I wish it were available for Android.

I don't see Nim support. Are you using the lsp plugin?

Thanks.


Re: What text editor are you using for Nim?

2019-08-05 Thread federico3
Neovim user here.


Re: Fastest Prime Sieve, in Nim

2019-08-05 Thread GordonBGood
@mratsim

> Not sure if it's the only bug but for now this is the one to fix for 
> multithreading on --newruntime #11844.

It seems that @Araq has pushed a commit to fix that issue; all that remains is 
to compile the DEVEL branch and test or wait for a new release...

As to exploring different alternative multi-threading:

> approaching the limits of OpenMP (nested parallelism especially)

I rejected OpenMP early as it is too C'ish and therefore somewhat cludgy 
although I have used it before with C and see how its use can be expanded 
beyond the basics available "out-of-the-box".

> raw Threads is a too low-level abstraction

At first I thought using the low-level would be the answer as in easily 
emulating GoLang's green threads and that channels would work like GoLang 
channels; however, it kept getting more complex due to the limitations of not 
having GoLang's multi-threaded GC and therefore all the Nim limiations on the 
use of channels, meaning that one has to stoop to the use of low level features 
as in use of Lock and Cond and essentially building a Nim version of Haskell's 
"MVar" to pass through the channels. This has caused me to explore @Araq's 
recommended threadpool.

> Nim's FlowVars have contention issues and no load balancing

Funny you should say that about FlowVar's as your link to the "pibench2" 
project doesn't use theadpool and therefore doesn't use FlowVar's. I agree that 
the linked project using the raw thread's isn't very efficient and should be 
re-written to use threadpool and spawn as per the following:


# Compute PI in an inefficient way but multi-theaded...
from cpuinfo import countProcessors
from threadpool import FlowVar, spawn, `^`
from times import epochTime

const DELTA = 1_000_000 # number of terms calculated per thread call!

let numprocs = countProcessors()

proc pi(numterms: int64): float =
  result = 0
  proc terms(k, klmt: int64): float {.inline.} =
result = 0
for i in countup(k, klmt, 2):
  let frst = i + i + 1; result += 1 / frst.float - 1 / (frst + 2).float
# [ # take out the space between the `#` and the `]` to comment this out!
  var rslt = newSeq[FlowVar[float]](numprocs) # acts as a rotary queue!
  for i in 0 ..< numprocs: # preload waiting queue!
let k = i * DELTA; let klmt = k + (if k + DELTA > numterms: numterms - 
k else: DELTA - 1)
rslt[i] = terms(k, klmt).spawn
  for i in 0 .. numterms div DELTA:
let id = i mod rslt.len; result += ^rslt[id] # get values from queue!
let k = (i + numprocs) * DELTA
let klmt = k + (if k + DELTA > numterms: numterms - k else: DELTA - 1)
rslt[id] = terms(k, klmt).spawn # add new tasks to queue! # ]#
#[ # put a space between the `#` and the `]` to uncomment this!
  for k in countup(0, numterms, DELTA): # do it without threading for 
comparison
let xtra = (if k + DELTA > numterms: numterms - k else: DELTA - 1)
result += terms(k, k + xtra) # ]#
  result *= 4

let start = epochTime()
let answr = pi(10_000_000_000)
let elpsd = (epochTime() - start) * 1000.0
echo answr, " in ", elpsd, " milliseconds."


Run

The above code does the same calculations as the "pibench2" with default 
settings which calculates 10^10 = 10 billion terms for 10 "digits". One can 
vary DELTA to see that it starts to lose scaling across threads at something 
below about a hundred thousand when the thread task is something about a 
millisecond.

The above takes about 3.X seconds on a Sandy Bridge CPU with three cores at 2.5 
Gigahertz to do a tenth of the job as per the following WandBox link: 
[https://wandbox.org/permlink/9gOlb1WsjjgWFGIm](https://wandbox.org/permlink/9gOlb1WsjjgWFGIm)
 but that isn't too certain as the two of the three threads will likely be 
shared cores; it takes about 54.2 seconds on my Intel Atom i5-Z8350 Windows 
tablet CPU (Silvermont) at 1.44 GHz and four cores and about 36.25 seconds on 
my Intel i3-2100 at 3.1 GHz with two cores and four threads. From all of that, 
your processor being a half again faster clock speed than this last and with 
nine times the number of cores as well as being seven generations newer might 
make your 18 core/36 thread machine able to run this in a half second but I 
would more expect it to be about two to three seconds. One can comment out the 
multi-threading code and uncomment the single threaded code to see that the 
code scales with the number of cores other than the uncertainty of 
Hyperthreading/Simultaneous Multi-Threading threads and the number of floating 
point execution units there are per core and how they are used by the CPU. It 
is easy to calculate from these times (especially single threaded ones) that it 
is taking about 30 CPU clock cycles per term calculation on these older 
generation CPU's so that seems about right and explains why we need at least 
about a hundred thousand