Re: Current status of Nim for Webassembly?

2019-10-26 Thread bluenote
> It seems to work...

Thanks for the link. Then maybe my question is: Under which circumstances would 
the Nim runtime not run at the root of the call stack? I still don't clearly 
see the patterns where Nim's GC can / cannot work.

Does the `EMSCRIPTEN_KEEPALIVE` play a role in this? What about taking the 
no-emscripten path as suggested by @arnetheduck and @yglukhov 
[here](https://forum.nim-lang.org/t/4779) \-- does the emscripten magic have an 
impact on the GC question?


Re: CSources are gone - How to bootstrap?

2019-10-24 Thread bluenote
Ah, thanks for clarifying -- not it works for me as well ;).


Re: CSources are gone - How to bootstrap?

2019-10-24 Thread bluenote
That's the same `build_all.sh` does, isn't it?

I just tried it again with the official `build_all.sh`:


git clone https://github.com/nim-lang/Nim.git
cd Nim
git checkout master
sh build_all.sh


Run

still fails for me when building koch:


bin/nim c koch
Hint: used config file '/tmp/Nim/config/nim.cfg' [Conf]
Hint: used config file 'koch.nim.cfg' [Conf]
Hint: system [Processing]
/tmp/Nim/lib/system.nim(207, 11) Error: undeclared identifier: 'is'


Run


Current status of Nim for Webassembly?

2019-10-24 Thread bluenote
There have been a few webassembly threads already, but it's a bit unclear to me 
what's the current status of targeting webassembly. For instance [this 
thread](https://forum.nim-lang.org/t/4399#27529) mentions:

> Nims garbage collector only works if the Nim runtime controls the root of the 
> call stack, if I understand the experts correctly. That's normally not the 
> case in the browser, but the fact that Nims GC is thread-local might save us 
> here...

How exactly can we setup a project so that "running at the root of the call 
stack" is accomplished? Does compiling via emscripten and loading the resulting 
JS glue code satisfy this criterion or not?


Re: CSources are gone - How to bootstrap?

2019-10-24 Thread bluenote
> The idea is that all the existing scripts that happen to not hardcode a 
> csources commit (which includes all of our own scripts...) continue to work 
> for good.

Do they work? My weekly CI's are failing for ~ half a year because Nim cannot 
be bootstrapped on the master branch from csources:

[https://travis-ci.org/bluenote10/NimData/builds](https://travis-ci.org/bluenote10/NimData/builds)


Re: Generic methods are deprecated?

2019-06-15 Thread bluenote
> AFAIK removal of generic methods is so that under-the-hood we can switch the 
> methods implementation to a vtable

But shouldn't a vtable be able to handle generics that are attached to the base 
just fine? For instance, the `Test` class has a vtable with a single slot for 
`call`. An instantiation `Test[int]` would point to an `int` instantiation of 
`call`, and a `Test[float]` would point to the `float` instantiation. To my 
knowledge that's how it works in C++.

On the other hand, generics not attached to the base, can result in multiple 
instantiations for a single method. This requires full program analysis, and 
doesn't play well with vtables.


Re: Best way to represent AST

2019-06-15 Thread bluenote
Or if you prefer inheritance, you can extend the inheritance tree:


type
  Node = ref object of RootObj
  
  LitOrOp = ref object of Node
  
  Number = object of LitOrOp
value: int
  
  BinOp = object of LitOrOp
left: LitOrOp
op: string
right: LitOrOp


Run


Generic methods are deprecated?

2019-06-09 Thread bluenote
I just noticed that something as simple as


type
  Test[T] = ref object of RootObj

method call[T](t: Test[T]) {.base.} = discard


Run

now generates a warning `generic methods are deprecated`.

All my relevant projects rely on generics with methods. Is there a plan for the 
future for such projects?


Re: Can I avoid covariance of typedesc arguments?

2019-04-27 Thread bluenote
I'm stupid, I totally forgot that there is the `T is A and A is T` trick that 
allows for exact type equality comparison. I still think it is a pity that the 
corresponding PR has been declined 
([https://github.com/nim-lang/Nim/pull/8612)](https://github.com/nim-lang/Nim/pull/8612\)).

@Stefan_Salewski: The actual background is somewhat involved. In the 
inheritance library I'm working on, there is a system to automatically perform 
super/base/parent class initialization. If there is an inheritance chain A => B 
=> C, I have to make sure that when C tries to call its parent constructor, it 
doesn't accidentally call the constructor of A. This would be possible due to 
covariance, and result in a bug because B isn't initialized. I'll probably just 
go for named constructors because it simplifies the problem. I was asking 
mainly to see what alternatives others use, and the error overload is indeed a 
nice solution in general.


Can I avoid covariance of typedesc arguments?

2019-04-27 Thread bluenote
Apparently typedesc arguments are covariant. For example:


import typetraits

type
  A = object of RootObj
  B = object of A

proc f(T: typedesc[A]) =
  echo "should only accept A, but not B"
  echo "T is A: ", T is A
  echo "name(T): ", name(T)

f(A)
f(B) # how to prevent this to compile?


Run

This compiles and prints:


should only accept A, but not B
T is A: true
name(T): A
should only accept A, but not B
T is A: true
name(T): B


Run

Is there an elegant solution so that I cannot accidentally invoke `f(B)`? The 
ideal solution (in my particular problem) would be to avoid the function match 
entirely. Otherwise some when + error statements might be needed, but `when T 
is A` doesn't work because it also returns true for subtypes, `when name(T) == 
name(A)` feels hacky.


Re: typed and untyped

2019-04-27 Thread bluenote
On input/argument side, the semantics are clear:

  * `untyped` passes in the raw AST without semchecking (no type information 
available)
  * `typed` performs symbol lookup before passing the argument (type 
information available)



On output side, I'm also confused. I usually only use `untyped` when the 
macro/template returns an arbitrary AST, and concrete types if it returns a 
typed expression.

The semantics of a `typed` return values has also been discussed here: 
[https://forum.nim-lang.org/t/4037](https://forum.nim-lang.org/t/4037)


Re: Side effects of typed macro arguments?

2019-04-16 Thread bluenote
Okay, thanks for the clarification. Than I think the most natural thing is to 
use blocks to get a limited scope.


Re: Side effects of typed macro arguments?

2019-04-16 Thread bluenote
Maybe I shouldn't have obfuscated the example by the two macro calls. Of course 
you're right: The first macro simply gets expanded to the typed macro call.

The actual use case is somewhat involved, but maybe not super relevant. I was 
mainly puzzled by the behavior, and I'm still wondering if it is a bug or 
intentional. Note that because typed argument actually affect the callsite you 
can do things like this:


macro takesTwo(a, b: typed): untyped =
  result = newStmtList()

takesTwo() do :
  let x = 1
do:
  x

# but don't dare to redefine x here ;)


Run

where one typed argument gets its type information from the evaluation of 
another argument. I'm wondering how much Nim code relies on that.


Side effects of typed macro arguments?

2019-04-16 Thread bluenote
Is it expected behavior that typed macro arguments have a side effect on call 
site? For example I was surprised that this code compiles:


macro typedMacro(body: typed): untyped =
  result = newCall(ident "echo", newStrLitNode "Hello World")

macro untypedMacro(body: untyped): untyped =
  result = newCall(ident "typedMacro", body)

untypedMacro():
  echo "here"
  proc test(x: int) =
echo x

test(1)


Run

My assumption was: I'm passing an untyped block into a macro and locally I just 
get the resulting AST `echo "Hello World"`. I didn't expect that `test` is 
defined afterwards, because it is not part of the final AST. Is that by design?

What is the best way to get side-effects-free typed arguments? Should I simply 
wrap them in a block?


Re: Problem with export marker and macros

2019-04-15 Thread bluenote
I was also looking for some postfix operator syntax in a DSL, and I noticed that


`*`


Run

(how to write that in as inline RST?) can actually be used. Looks like a 
postfix operator, but semantically it is just an `AccQuoted` argument to the 
preceding `Command` node. In your case:


activations:
  act sigmoid`*`:
fn: 1 / (1 + exp(-x))
deriv: fx * (1 - fx)
  act tanh`*`:
fn: tanh(x)
deriv: (let t = tanh(fx); 1 - t * t)


Run

The relevant part of the AST is:


Command
  Ident "act"
  Command
Ident "sigmoid"
AccQuoted
  Ident "*"


Run

Slightly non-standard, but works well in my purpose and looks even better in an 
editor with special syntax highlighting for acc-quoted ops.


Re: How to immutably initialize parent object with private fields?

2019-04-13 Thread bluenote
@Araq: Great to hear that there is some activity regarding write tracking, my 
most anticipated Nim feature ;).

I think this is an independent problem though, that rather relates to object 
construction / initialization, not really related to immutability (my title was 
misleading). I'm not sure if it is worthy of a RFC, but I tried to sum it up 
more clearly here:

[https://github.com/nim-lang/RFCs/issues/145](https://github.com/nim-lang/RFCs/issues/145)

It could very well be that I'm missing something ;).


Re: closure_methods: OOP purely based on closures

2019-03-29 Thread bluenote
I didn't know that this can be solved by forwarding from one macro to another, 
will try that, looks really nice.

I will experiment a bit more regarding the field accessors when I'm back from 
vacation. Overall this has a bit lower priority to me, because the use cases I 
have barely require plain getter/setter. If a situation requires exposing raw 
data, plain objects are a perfectly fine solution already. I'd use this closure 
based approach exactly when I want to hide raw data behind an abstract 
interface.


Re: closure_methods: OOP purely based on closures

2019-03-28 Thread bluenote
@gemath That's also something I had in mind ;).

The problem with autogenerating getters/setters for `var x*` expressions is 
that closures don't allow the regular `field` / `field=` syntax as far as I can 
see. For instance:


type
  Obj = ref object
step: proc(): int
`step=`: proc(x: int)

let o = Obj(step: proc(): int = 0, `step=`: proc(x: int) = echo x)
echo o.step()
o.`step=`(1)  # I guess only this syntax is possible


Run

So you cannot just use something nice like `o.step = 1`. Thus, it's probably 
better to use different names for the getter and setter. The auto-generated 
getter/setter could follow a fixed convention like `step`/`setStep` or 
`getStep`/`setStep`. In the end I preferred to give the user control over how 
they call them with the current getter/setter shortcuts.

I also tried to use the `Counter of SomeBaseClass` syntax, but for the overload 
analysis it is important to pass in the base class as a `typed` macro argument. 
`Counter of SomeBaseClass` would require an `untyped` argument, and I don't 
think it would be possible to access the type impl in this case. That's why I 
went for the slightly less appealing `classOf(Sub, Base)` syntax, and that's 
also why generic subclasses will probably require a minor repetition 
`classOfGeneric(Sub[X, Y], Base, Base[X])` \-- the first appearance of `Base` 
is a typed arg, the one with the generics is untyped.


Re: closure_methods: OOP purely based on closures

2019-03-28 Thread bluenote
So far I only ran some stupid benchmarks on dispatch speed 
[here](https://github.com/bluenote10/closure_methods/blob/master/benchmarks/basic_dispatch_closures.nim).
 and in that terms using closures is a bit faster than the branch based 
dispatch of methods, even if the number of subclasses is still low (but nothing 
substantial).

Obviously using closures is the wrong tool if a problem requires raw field 
access in tight loops (e.g. vector math library). The design rather aims at use 
cases that are well suited for OOP abstraction, for instance a React-like web 
components library, where field access is negligible.

Do you have a good idea of a benchmark that neither focuses too much on field 
access nor on the O(1) vs O(N) dispatch difference?


Re: Owned refs

2019-03-28 Thread bluenote
I really like the proposal, but I may not fully understand the core idea ;). 
What exactly do you mean by:

> In a release build the RC operations can be left out and with a type based 
> allocator we still have memory safety!

Does this refer to memory safety as in "no memory leaks" or as in "no memory 
corruption"? I always thought it is the latter.

What would happen for instance in this example:


var n: owned Node = fromSomewhere()
let dangling = unowned(n)

if random() > 1e5:
  # imagine lots of code here
  dangling = nil
else:
  # imagine lots of code here
  # but programmer forgets to remove the unowned ref

# reassignment => free old owned Node
n = Node(data: 4)

if not dangling.isNil():
  echo dangling.data


Run

In a debug build, the reassignment would lead to an abort if we ever execute 
the unlikely branch that forgets to remove the ref. But in a release build the 
last line would read corrupted memory, wouldn't it? Just because it points to 
memory of the right type, it doesn't mean that it is not an issue?


closure_methods: OOP purely based on closures

2019-03-27 Thread bluenote
Yet another OOP macro ;). [*]

I was wondering if it would be possible to write classes in Nim entirely by 
using closures. A good opportunity to work on my meta programming skills. At 
first the approach looked a bit weird, but now I feel that the resulting DSL 
might actually work quite well. What do you think?

[closure_methods](https://github.com/bluenote10/closure_methods)

[*] Actually I was searching for OOP macros on Nimble but couldn't find much...


Re: How to immutably initialize parent object with private fields?

2019-02-21 Thread bluenote
@Rania_d Note that the issue you linked is only a problem in languages that 
don't allow named parameters. It's not a problem in Nim because it has named 
parameters, so no need for the builder pattern.

Nim's problem is rather that it doesn't allow to combine immutable objects with 
inheritance out of the box.

@gemath Good idea, so it comes down to either setting the additional fields of 
the parent object vs the fields of the derived object.


Re: How to immutably initialize parent object with private fields?

2019-02-15 Thread bluenote
> The accessor are only visible for the internal library proc but not exported 
> outside of the library.

In this case I cannot rely on hiding the fields via re-exporting, because the 
library is by design supposed to be extended on user side. Think of an UI 
component library, where users should be able to define their own components.

@lscrd Good points about the runtime checks, but yes compile time security 
would be preferred.

I have now found two solutions that seem to satisfy the requirements:

1\. Macro solution:


# on lib side
template privateInitializer(element: typed, idString: string): untyped =
  element.id = idString
  element

macro newElement*(T: typedesc, id: string, args: varargs[untyped]): untyped 
=
  # convert varargs into an object constructor call of T
  let constructor = newTree(nnkObjConstr)
  constructor.add(T.getTypeInst[1])
  for arg in args:
expectKind(arg, nnkExprEqExpr)
constructor.add(newColonExpr(arg[0], arg[1]))
  # apply post construction initialization of parent fields
  result = newCall(bindSym"privateInitializer", constructor, id)

# on user side
newElement(ElementA, id="A", a=1)


Run

2\. Template solution with an explicit check that only object constructors are 
passed in:


# on lib side
macro verifyObjectConstructor(x: typed): untyped =
  if x.kind != nnkObjConstr:
error($x.repr[0..^1] & " is not an object constructor")

template newElement*(idString: string, constructor: typed): untyped =
  verifyObjectConstructor(constructor)
  let element = constructor
  element.id = idString
  element

# on user side
newElement("A", ElementA(a: 1))

# abusing the template as an arbitrary setter is now a compile time error:
let el = ElementA(a: 1)
newElement("A", el)


Run

@Araq: What is your opinion on this? I'm wondering if it would make sense to 
differentiate visibility for construction vs field access. As far as I can see 
a lot of visibility problems would be solved if there was an intermediate 
between fully-hidden and fully-exposed which is "exposed in object 
construction". Would it for instance make sense to have


type
  Element* = ref object of RootObj
id {.initializable.}: string


Run

so that public access to `id` is prevented in general, but `id` can be passed 
into the constructor including subtype constructors?


Re: How to immutably initialize parent object with private fields?

2019-02-14 Thread bluenote
@lscrd: The `initElement` is also a setter despite its name ;). You cannot stop 
users from calling `element.initElement("different id")` and mutating the field 
at any point in time, which is what I'm trying to avoid.

In fact that is also true for my template constructor idea via 
`newElement("different id", existingElement)`. If anything the template makes 
it a bit less obvious. Maybe what I really need is a macro taking a 
typedesc/generic and a list of constructor args that are forwarded to the 
subtype construction. Then the macro can really only be used for constructing 
new elements with injected `id` modifications.


Re: How to immutably initialize parent object with private fields?

2019-02-14 Thread bluenote
@Stefan_Salewski: That what I meant with mutable setters ;). I'm trying to 
avoid them so that user can cannot arbitrarily reset the field.

I finally had an idea that I can at least abstract away the mutation of the 
field:


# in lib.nim
template newElement*(idString: string, body: typed): untyped =
  let element = body
  element.id = idString
  element


Run

On user side construction now works like this:


type
  ElementA = ref object of Element
a: int
  ElementB = ref object of Element
b: int

proc newElementA(): ElementA =
  newElement("A", ElementA(a: 1))

proc newElementB(): ElementB =
  newElement("B", ElementB(b: 2))


Run

Not sure if there is something nicer, but this doesn't look too bad to me...


How to immutably initialize parent object with private fields?

2019-02-14 Thread bluenote
I'm running into this problem in every project of mine, and I simply can't find 
a good solution, although the problem seems very basic.

Let's say I write a dummy `lib.nim` like this:


# The lib provides a definition of an abstract base type
# without any actual instantiations...
type
  Element* = ref object of RootObj
# Example for a field that should be an implementation
# detail, used only internally in `lib`. It should
# neither be public nor should there be getter/setter
# so that we can rely on the fact that it does not
# change after construction.
id: string

proc run*(elements: openarray[Element]) =
  for element in elements:
echo "Touching element: " & element.id


Run

The library is intended to be instantiated on user side, for example:


import lib

type
  ElementA = ref object of Element
  ElementB = ref object of Element

# But how to construct them?

proc newElementA(): ElementA =
  ElementA(id: "A")

proc newElementB(): ElementB =
  ElementB(id: "B")

let elements = @[
  newElementA().Element,
  newElementB(),
]

run(elements)


Run

This doesn't compile because the user has no access to `id` at all, even in the 
constructor. Usually I provide a constructing proc in the scope of the type, 
e.g.:


# in lib.nim
proc newElement*(id: string): Element =
  Element(id: id)


Run

Now users can construct an `Element`, but I'm not sure if it helps constructing 
subtypes. This crashes at runtime with an invalid conversion (kind of expected):


proc newElementA(): ElementA =
  result = newElement("A").ElementA


Run

I also don't want to add setter procs/templates to `lib.nim` because than the 
field gets fully exposed.

Am I missing some basic template/macro tricks to solve this basic problem? I 
have spend hours going back and forth making fields private and public again or 
moving code around because I can't seem to get the visibility right.


Re: watchcode: not written in Nim, but at least for Nim ;)

2019-01-27 Thread bluenote
No particular challenge, really. In the end I went for the Python solution 
because (1) the problem is too trivial to require a serious language, (2) the 
result is arguably more accessible, (3) was a bit faster to write because the 
file monitoring libraries in Nim aren't quite as mature. I just wanted to have 
it done quickly to use it for other Nim projects.


watchcode: not written in Nim, but at least for Nim ;)

2019-01-27 Thread bluenote
I have just published a small project called 
[watchcode](https://github.com/bluenote10/watchcode). As an exception, it's not 
a Nim project, but it was written 100% with Nim in mind ;). I was never fully 
satisfied with other solutions for code watching/rerunning, so I had to give it 
a go and I'm quite happy with the result. Maybe it is useful for other Nim 
developers as well.


Re: Should we get rid of style insensitivity?

2018-11-19 Thread bluenote
I would have been interested in a vote, but apparently I'm the minority ;).

Personally I find the case insensitivity very off-putting and it was one of the 
reasons why I stayed away from Nim the first times I came across it.

> I appreciate when Nim forgives me a typo

That's my main concern about it. I like consistency, and I don't want 
inconsistent naming in my code base. I want the compiler to help me get it 
right exactly.

I never saw it as a feature, rather a quirk that I can live with. Yet, 
sometimes I still feel like I'm manually doing the work of the compiler when 
I'm double checking that I use consistent style. And I get distracted when 
reading foreign Nim code that switches between equivalent names for no apparent 
reason, especially when done in a local scope, where the syntax becomes 
obviously inferior to a consistent naming.


Re: Are there examples of the 'Elm architecture' for Nim?

2018-09-10 Thread bluenote
I had also written some small demos here: 
[https://github.com/bluenote10/KaraxExamples](https://github.com/bluenote10/KaraxExamples)


Re: TechEmpower Web Framework Benchmarks: Round 10

2018-03-24 Thread bluenote
Doesn't the compiler pick up this file? 
[https://github.com/tbrand/which_is_the_fastest/blob/master/nim/jester/server_nim_jester.nim.cfg](https://github.com/tbrand/which_is_the_fastest/blob/master/nim/jester/server_nim_jester.nim.cfg)


Re: Introducing loopfusion: loop over any number of sequences of any single type.

2018-03-19 Thread bluenote
Looks interesting, but why does the macro generate a for loop plus a zip 
iterator (which itself contains another for loop) instead of just a single for 
loop with injected symbols?


forEachIndexed j, [x, y, z], [a, b, c]:
  body

# would expand to:

for j in 0 ..< commonLengthWithSanityCheck(a, b, c):
  let x = a[j]
  let y = b[j]
  let z = c[j]
  body


Note: The length of `b` in your example differs. I was wondering if this is not 
handled, but I think it is, so probably just a typo .

Syntactically I would prefer something that aligns the loop variables with the 
containers, i.e.,


forEachIndexed j, x in xs, y in ys, z in zs:
  ...



Re: constness of refs & ptrs

2018-01-31 Thread bluenote
I would also be interested in a bit more information on writetracking, it seems 
like a perfect solution to the constness problem. How can it be enabled and 
what is the current status/plans?

> At this point we don't need more features that don't pull in their weight.

That's surprising. I think solving the ref constness problem for good would 
have a huge benefit, it always felt like a big missing piece in Nim. I was 
hoping this would make it into version 1, especially because it sounded like 
writetracking is the foundation for move semantics etc.


Re: block expression

2018-01-31 Thread bluenote
There should be no need for such a template, this must be a regression.

Since [this PR](https://github.com/nim-lang/Nim/pull/6695/files) blocks should 
be an expression (see [corresponding 
issue](https://github.com/nim-lang/Nim/issues/3827)). There is also a test 
case. However the test case indeed seems to fail now on devel, not sure if 
testament somehow ignores the test...


Re: Macros: How to parse a string and get the type of the expression?

2017-11-19 Thread bluenote
Ah, I think I found a solution:


import macros, strutils

macro typecheckedAst(x: typed): untyped =
  echo "calling typecheck on expression: ", x.repr
  echo "with type: ", x.getType().treeRepr()
  # We can build a type specific AST here:
  let typ = x.getType()
  if sameType(typ, bindSym"int"):
echo "it's an int"
result = newStrLitNode("AST for int")
  elif sameType(typ, bindSym"string"):
echo "it's a string"
result = newStrLitNode("AST for string")
  else:
echo "unknown type"
  echo " => resulting type dependent AST: ", result.repr

macro fmt*(fmt: static[string]): untyped =
  let fields = fmt.split(":")
  assert fields.len == 2
  let lhs = fields[0]
  let rhs = fields[1]
  # We probably can't get the type of `e` here, but we can delegate
  # all type specific AST generation into the `typecheckedAst` macro
  let e = parseExpr(lhs)
  result = newCall(ident"typecheckedAst", e)

block:
  let x = 1
  echo fmt"x + x:"

block:
  let x = "test"
  echo fmt"x & x:"


So the trick is to use `parseExpr` in the outer macro and delegate the type 
specific AST generation into a sub-macro which takes a `typed` expression.


Re: Macros: How to parse a string and get the type of the expression?

2017-11-19 Thread bluenote
@planhths: What I'm looking for is the slightly more advanced version of that, 
i.e., a macro that generates a different AST depending on the type of that 
`parseExpr(v)` in your example.


Re: Macros: How to parse a string and get the type of the expression?

2017-11-19 Thread bluenote
Sorry for bumping an old thread, but it's for a good reason (the [string 
interpolation PR](https://github.com/nim-lang/Nim/pull/6507)). I'm still 
struggling to achieve the same from within a macro:


macro parse(x: string): untyped =
  echo "calling parse on: ", x
  result = parseExpr(x.strVal)

macro typecheck(x: typed): untyped =
  echo "calling typecheck on: ", x.getType().repr()
  result = newStmtList()

template stringParseTest(x: string) = typecheck parse x

macro fmt*(fmt: static[string]): untyped =
  let fields = fmt.split(":")
  assert fields.len == 2
  let lhs = fields[0]
  let rhs = fields[1]
  echo "Trying to get type of: ", lhs
  # Neither of the following works, because the ``x.strVal`` produces:
  # Error: field 'strVal' cannot be found
  # Also, it is strange that the value of x within parse is "lhs" and not
  # its actual value.
  when false:
let lhsType = stringParseTest(lhs)
  when false:
let lhsType = typecheck(parse(lhs))
  when false: # in general calling parse doesn't seems to work due to the 
value issue:
parse(lhs)
  # So it looks like I have to call parseExpr directly here. This gives the 
expected
  # result for the expression, but calling typecheck on it does not work, 
because of:
  # Error: expression '' has no type (or is ambiguous)
  when false:
let e = parseExpr(lhs)
echo e.treeRepr
let lhsType = typecheck(e)
  # Similarly any attempt to call getType() directly on the expressions 
fails with
  # node has no type.
  when false:
let e = parseExpr(lhs)
echo e.treeRepr
let lhsType = e.getType()

block:
  let x = 1
  fmt"x + x:"

block:
  let x = "test"
  fmt"x & x:"


I feel like I'm just missing the right kind of nesting. Or maybe it isn't 
possible when the outer-most thing is a macro, and I really need to wrap 
everything into another outer template?


Re: floating point output formating

2017-11-07 Thread bluenote
@jzakiya: Do you think that is helpful: 
[https://github.com/nim-lang/Nim/pull/6704](https://github.com/nim-lang/Nim/pull/6704)


Re: floating point output formating

2017-11-06 Thread bluenote
@Udiknedormin I strongly think it should be part of the language. Developers 
fear dependencies[*], so people will continue to use workarounds instead of 
using string interpolation via an external dependency. Also, the Nim core 
itself could benefit from it in some places ([random 
example](https://github.com/nim-lang/Nim/blob/87a46765eee6601ccc53b2c38d1c8f3a9b045124/lib/system/nimscript.nim#L285)
 or every line with more ~5+ concatenating `&` and the notorious opening and 
closing `"`). Sometimes I don't embed helpful information in my exception 
strings, because typing out the manual concatenation is tedious (and I don't 
want to add a dependence for just 1 line of code), whereas in e.g. Scala I 
would, because it is so easy (`f"Error: blah blah because x = $x and y = $y 
while running in mode '$mode'"` if I counted correctly that would take 6 `&` 
and 8 `"` in Nim). It's a general pattern that in languages where string 
interpolation is included, developers tend to produce higher quality output 
strings on average compared to languages where there is a larger barrier for 
achieving the same.

[*] I'm an author of one of the string interpolation libs out there, but I've 
never dared to use it in my other libraries because of dependency avoidance 


Re: floating point output formating

2017-11-05 Thread bluenote

import strutils
let num = 10.123456789
echo num.formatFloat(ffDecimal, 4)



Re: floating point output formating

2017-11-05 Thread bluenote
And hopefully we will soon have string interpolation in Nim 
([PR](https://github.com/nim-lang/Nim/pull/6507)). Then it would be something 
like this (or similar, language is still in discussion):


echo "$x%.4f"



Re: Has anyone considered if Nim would be a good fit for a "serverless" architecture?

2017-11-01 Thread bluenote
I was experimenting with distributed computing a bit. The idea is slightly 
different, because the same binary has to be published to each cluster node and 
it can run in different roles client/master/worker. It's far from being usable, 
but at least it can already publish data into worker memory and run arbitrary 
code remotely on a worker. Usage looks like that: 
[https://github.com/bluenote10/Hydra/blob/master/testapp1.nim](https://github.com/bluenote10/Hydra/blob/master/testapp1.nim)


Re: Cannot get name of type using typedesc

2017-10-23 Thread bluenote
I think your third example should work if you `import typetraits`.

Actually let's test the forum feature...


import typetraits

proc test3*(T: typedesc) =
  echo(T.name)

test3(int)



Re: DSL for generating/animating SVG/GIF

2017-09-20 Thread bluenote
Good point, I didn't think of the JS backend so far.


Re: Introducing Reel Valley

2017-09-20 Thread bluenote
> @bluenote, thank you! I wonder based on what you made that quality assumption 
> though

The high quality media?  I assume what I saw was partly in-game graphics.


Re: Introducing Reel Valley

2017-09-19 Thread bluenote
I'm not on Facebook, so I can't really judge, but from what I could see this 
looks like super high quality, really impressive.


DSL for generating/animating SVG/GIF

2017-09-19 Thread bluenote
Just to let you know: The next time you have to work on some 
graphics/illustrations/animations, you can do so in Nim .

[https://github.com/bluenote10/NimSvg](https://github.com/bluenote10/NimSvg)


Re: FSMonitor

2017-09-11 Thread bluenote
I wish we could go down the other route and make `fsmonitor` cross-platform by 
abstracting away the inotify stuff. The reason why having it in the standard 
library could be beneficial: One of the things I'm missing the most compared to 
Scala development is SBT's `~compile`/`~run`/`~test` functionality, which 
allows to easily set-up source code watchers and re-run the compiler (and 
optionally arbitrary entry points or tests) whenever the source code changes.

If the functionality gets pushed into third party libraries it will be even 
more difficult to integrate such functionality by default into Nim's build 
approaches. I currently always fall back to hacky/non-cross-platform 
bash+inotify or even nodejs based watchers, and it would be much nicer if 
source code watching could become standard nimscript functionality. I have it 
on my todo list to look into that, but I'm not sure when I can get to work on 
it. Wasn't there a thread asking for some beginner challenges, maybe that would 
work?


Re: optional int parameters for a proc

2017-08-26 Thread bluenote
Actually there's no need for external libs or rolling your own solution. The 
standard library has an `Option[T]` and is exactly suited for this.


What assumption can be made on pointers returned by getTypeInfo?

2017-07-22 Thread bluenote
Given two types A and B, is it safe to assume that the following holds over the 
entire runtime of a program: Type A == Type B if and only if the pointers 
returned by `getTypeInfo` are the same? Or is it possible that e.g. the pointer 
`getTypeInfo(anInt)` can point to different addresses over the course of 
execution.

Background: I need to maintain a hash table, where the keys are types. If it is 
safe to make this assumption the addresses themselves could be used as a hash 
instead of actually comparing the underlying `PNimTypes` (implementing such a 
types comparison looks tricky on first glance, or is this already solved 
somewhere within Nim)?


Re: nim-random not that random at all?

2017-07-19 Thread bluenote
Are you on Windows? My guess is that this is mainly an issue of `randomize` and 
the low resolution of the timer used for initialization 
[here](https://github.com/nim-lang/Nim/blob/47a7f2fff795be3c4c28059cfa573f5d6069af44/lib/pure/random.nim#L126).


Re: Caller line numbers in templates?

2017-07-15 Thread bluenote
I'm just trying to figure out exactly the same. Did you find a solution to that?


Re: Arraymancer - A n-dimensional array / tensor library

2017-07-15 Thread bluenote
A late reply because I was hoping to dive into this a bit deeper before 
replying. But due to lack of time, a high-level feedback must suffice: This 
looks awesome!

I completely agree with your observation that there is a gap between developing 
prototypes e.g. in Python and bringing them into production -- not only in deep 
learning, but data science in general. And I also think that Nim's feature set 
would be perfect to fill this gap.

A quick question on using statically-typed tensors: I assume that this implies 
that the topolgy of a network cannot be dynamic at all? I'm wondering if there 
are good work-arounds to situations where dynamic network topologies are 
required, for instance when a model wants to choose its number of hidden layer 
nodes iteratively, picking the best model variant. Are dynamically typed 
tensors an option or would that defeat the design / performance?


Re: Import from parent directories

2017-07-15 Thread bluenote
I'm not sure if I understand the question correctly. An example project 
structure:


submodA/submodA.nim
submodB/submodB.nim
parent.nim


Now you can do in `submodA.nim` for instance:


import ../parent
import ../submodB/submodB


Maybe your file names require to put the paths in quotes?


Re: How to transform compile time into runtime data

2017-07-11 Thread bluenote
Thanks guys, good suggestions, that should do the job.


How to transform compile time into runtime data

2017-07-11 Thread bluenote
I'm working on exactly the same problem as @andrea did a [while 
ago](https://forum.nim-lang.org/t/1560) (registering procs at compile-time) and 
I'm running into the same difficulty: How can I capture the content of a 
compile time variable at the end of the entire compilation and turn it into a 
runtime variable.

Imagine there is a `remote.nim` module (omitting ids & mapping):


import macros

var registeredProcs {.compileTime.} = newSeq[string]()

macro remote*(n: untyped): untyped =
  let procName = n[0]
  registeredProcs &= $procName
  echo registeredProcs
  result = n

proc square(x: float): float {.remote.} = x * x
proc cubic(x: float): float {.remote.} = x * x * x

# this compiles, but it doesn't really work
const procs = registeredProcs

proc genericCall*(id: string, x: float): float =
  echo "looking up ", id, " in ", procs
  for funcId in procs:
if id == funcId:
  echo "would call id: ", funcId

# locally in this module it works fine
discard genericCall("square", 1)
discard genericCall("cubic", 1)


The problem is that external usage doesn't seem to work. I.e., if there is a 
`user.nim`:


import remote as remote_module

proc userSquare(x: float): float {.remote.} = x * x
proc userCubic(x: float): float {.remote.} = x * x * x

discard genericCall("userSquare", 1)
discard genericCall("userCubic", 1)


I can see that the usages of `{.remote.}` on client side do modify the 
`registeredProcs`, but I can't seem to capture them as well in the runtime 
variable `procs`. Any ideas how to approach this? I feel like I need to run 
some static code after everything else is compiled, but that is probably 
impossible. 


Re: Add Nim to The Computer Language Benchmarks Game?

2017-06-25 Thread bluenote
I was a bit annoyed that they ban certain languages from their "game", so I 
started to collect my own set of silly benchmarks (plus a framework to make 
defining, running, and visualizing benchmarks easy):

[https://bluenote10.github.io/SimpleLanguageBenchmarks](https://bluenote10.github.io/SimpleLanguageBenchmarks)/

The goal was to have a different focus by benchmarking simple/idiomatic 
implementations, e.g. to find out what performance I can expect from standard 
libraries in different languages. The Benchmark Game mainly compares what you 
can achieve over years of optimization => not the performance you get when you 
start out in a language. Unfortunately, I didn't get too far with the project, 
but Nim already looks really good . If anyone is interested in adding more 
benchmarks/implementation we could just run our ban-free benchmark suite.


Re: Do notation without parentheses

2017-06-07 Thread bluenote
Most likely this is not really intended. For instance, this now compiles, but 
produces invalid C code:


import future

proc takesFunc(f: () -> void) =
  f()

takesFunc do:
  var x = 1

echo x


Probably best to track this as an issue: 
[https://github.com/nim-lang/Nim/issues/5963](https://github.com/nim-lang/Nim/issues/5963)


Re: Linear algebra library

2017-06-06 Thread bluenote
That's looking great. How does the scope of the two compare exactly?


Re: Do notation without parentheses

2017-06-06 Thread bluenote
> The code tries to pass a parameter with the wrong type to that proc, yes. But 
> the compiler doesn't even get that far:

I'm not sure about that. So with having just one body or no conflicts you would 
expect a type error? But this compiles and works just fine:


import future

proc takesFunc(f: () -> void) =
  echo "running f()"
  f()
  echo "done running f()"

takesFunc do:
  var x = 1
  echo x

takesFunc do:
  var y = 2
  echo y


Output:


running f()
1
done running f()
running f()
2
done running f()



Do notation without parentheses

2017-06-06 Thread bluenote
I'm still getting confused about the do notation. In particular I'm surprised 
that the following gives an error "redefinition of x":


import future

proc takesFunc(f: () -> void) =
  f()

takesFunc do:
  var x = 1

takesFunc do:
  var x = 1


The manual mentions something that `do` without parenthesis is just a block. I 
don't understand that, what is the compiler passing to the function in this 
case?

Adding some empty parentheses after the `do` solves the problem, but if the 
version without the parentheses is not creating an anonymous proc, shouldn't 
this lead to a more meaningful error? Otherwise finding such a bug is a bit by 
chance like in my case with the redefinition.


Re: Tell Visual Studio Code to use JS backend?

2017-06-04 Thread bluenote
Ignore me: Overloading on `string` and `cstring` does not make much sense here. 
Problem solved by omitting the `string` version...

Would still be interested in the backend config question though.


Tell Visual Studio Code to use JS backend?

2017-06-04 Thread bluenote
I'm currently experimenting with wrapping some JS test framework. A minimal 
example:


import future

proc describe(description: cstring, body: () -> void) {.importc.}
proc describe(description: string, body: () -> void) =
  describe(description.cstring, body)

proc it(description: cstring, body: () -> void) {.importc.}
proc it(description: string, body: () -> void) =
  it(description.cstring, body)

type
  Expect = ref object

proc expect[T](x: T): Expect {.importc.}

proc toBe[T](e: Expect, x: T) {.importcpp.}


describe("The test suite"):
  
  it("should work"):
var a = 1
expect(a).toBe(1)


When using the JS backend, this compiles and works pretty well already. However 
using the standard `c` backend, this produces an error `Error: internal error: 
environment misses: a`. Two questions:

  * Should we bother that it doesn't compile with `c`? Known issue? I think 
part of the problem is that the `describe` and `it` functions have been 
overloaded with both `string` and `cstring`.
  * When writing some larger test code, the Visual Studio Code linter flags 
this internal error for almost every line of code, which is pretty annoying to 
work with. Typically I can use `.nims` or `nim.cfg` to modify the way Visual 
Studio Code compiles (or rather "nimsuggests") a file, e.g., for define 
switches. I was trying to find a way to configure the backend as well from the 
config files, but I haven't found a way yet. Is this possible?




Re: Surprising floating point equality

2017-05-15 Thread bluenote
I would agree that this is not quite as expected. In the generated C code, the 
47.11'f32 literal becomes 4.7109e+01, i.e., it has higher precision 
than `y`. One might think that an explicit conversion should help, but I think 
it is optimised away. If you need a work-around, wrapping the conversion in a 
function does work:


proc forceF32[T](x: T): float32 = x.float32

let y: float32 = 47.11'f32 # the 'f32 actually doesn't matter
assert forceF32(47.11'f32) == y # ok
assert float32(47.11'f32) == y # fails



Re: Announcing Karax -- Single page applications for Nim

2017-05-14 Thread bluenote
In fact, it is maybe not even too far away:


include karaxprelude
import jstrutils, dom, future

type
  Model = ref object
toggle: bool
  
  EventHandler = (Event, VNode) -> void
  EventHandlerModel = (Model, Event, VNode) -> void


proc curry(handler: EventHandlerModel, model: Model): EventHandler =
  result = (ev: Event, n: VNode) => handler(model, ev, n)

proc onClick(model: Model, ev: Event, n: VNode) =
  kout(ev)
  kout(model)
  model.toggle = model.toggle xor true

proc view(model: Model): VNode =
  result = buildHtml():
tdiv:
  button(onclick=curry(onClick, model)):
text "click me"
  tdiv:
text "Toggle state:"
  tdiv:
if model.toggle:
  text "true"
else:
  text "false"

proc runMain() =
  
  var model = Model(toggle: true)
  
  proc renderer(): VNode =
# var model = Model(toggle: true)   # init here does not work
view(model)
  
  setRenderer renderer

runMain()


At first I was initializing the `model` in the renderer proc. This had the 
result that the view never updated -- it's not immediately clear to me why it 
has to be in the outer scope.

Adding an Elm-like message approach should also be possible by constructing 
some `Msg` in each event handler and calling an `update` function. Okay, in 
contrast to Elm the model is updated in-place, but maybe it is even beneficial 
to keep the model update close to how it works natively.

The only issue is that every event handler has to be curried. So my question 
probably becomes: Is it possible to automatize this "injection" of the model 
into the event handlers, so that an event handler `(Model, Event, VNode) -> 
void` can be passed directly to `on...`.


Re: Announcing Karax -- Single page applications for Nim

2017-05-14 Thread bluenote
@Araq: Sound very interesting, really looking forward in which direction this 
will develop. +1 for the Elm inspiration and not following the the 
one-file-component path. And compared to Elm, the Nim syntax really shines for 
the templating stuff.

I've been wondering for some time, if it would be possible to achieve a design 
which is even closer to the Elm architecture? On first glance it would be so 
nice to write stuff like this:


type:
  Model = object
# ...
  
  Msg = object
# typically an object variant

proc init(): Model = ...

proc update(msg: Msg, model: Model): Model = ...

proc view[Msg](model): Html[Msg] = ...

karax.runMain(init, update, view)


Are there any plans to go in that direction or are there technical obstacles 
which prevent such a design?


Re: Announcing Karax -- Single page applications for Nim

2017-04-23 Thread bluenote
Indeed, great idea!

Did you had a look at Vue for inspiration? Many people consider it the next big 
thing after React, and in terms of performance it has already [raised the 
bar](https://vuejs.org/v2/guide/comparison.html#Performance-Profiles) a bit.

But performance is typically not the most important aspect for choosing a JS 
framework. Probably karax would benefit the most by making it more accessible 
to JS users. Some random questions (not necessarily to be answered here, just 
points for documentation).

  * How to interact with third party JS libraries? (A general question that is 
most likely answered in the JS backend documentation itself; just to point out 
that it is one of the first questions that come to mind, and linking it from 
karax would be good.)
  * How does state handling work. In a Vue/React component, I know pretty much 
were to look for state, in the examples I find it very hard to see.
  * Why aren't components split into template/code(/style)?
  * How do components communicate?
  * What about the tooling, i.e., how does building / bundling / browser test 
running / debugging (source maps) work? An idea for the documentation would be 
to map JS artefacts like npm/webpack/mocha/karma/selenium to possible solutions.
  * By the way, my first thought when looking at the code was: All cstring 
here, I'm scared -- wait, it's not even compiling to C? I think I get now why 
it has to be like that, but getting rid of that c could definitely reduce the 
scare factor for newbies .




Re: Plans regarding named tuples

2017-02-27 Thread bluenote
Ah, maybe my assumptions were just wrong. All I knew was that something like 
this is not possible:


# can't use `Anonymous` as return type
proc test(): Anonymous =
  type Anonymous = object
x: int
y: int
  result = Anonymous(x: 0, y: 0)


But it looks like objects can already be anonymous, because this seem to work:


proc test(): auto =
  type Anonymous = object
x: int
y: int
  result = Anonymous(x: 0, y: 0)


Not being able to write out the type explicitly feels weird though. And things 
get messy when structural equivalence matters:


proc testA(): auto =
  type Anonymous = object
x: int
y: int
  result = Anonymous(x: 0, y: 0)

proc testB(): auto =
  type Anonymous = object
x: int
y: int
  result = Anonymous(x: 0, y: 0)

# this works
echo testA() == testA()

# this doesn't
echo testA() == testB()


So maybe objects aren't too far away to replace named tuples already. But I 
have to say that I still like the simplicity of named tuples a lot and will 
surely miss the nice syntax .


Re: Plans regarding named tuples

2017-02-27 Thread bluenote
> Please elaborate.

I'm mainly aware of the situation in Scala, where the lack of named tuples is 
the reason why type-safe schema transformation is rather limited. When working 
with typed data, there are basically two options:

  * Use unnamed tuples, which is not really an option, because it either 
hard-codes column positions (=> unreadable) or requires tedious pattern 
matching over all fields.
  * Use (case) classes, which is the standard solution: You write out a case 
class, which involves typing out all the field names/types once. The problem is 
that transforming the data cannot be done automatically. Let's assume the input 
data has 30 columns, so we have to write a first class RawInput with 30 fields. 
In a later processing step we might want to remove a few columns. This again 
requires to define a new class ReducedInput with 20+ fields. Eventually we 
might want to add a bunch of derived columns, and again we have to introduce a 
new type. The problem can be mitigated by inheritance/traits, but it still 
remains a work-around which is not very convenient to work with.



In Nim, the same can be solved very elegantly by just transforming/constructing 
named tuples everywhere. That's what the DSL looks like:


# A const schema definition is required once. Ideally this is the
# only point where we have to type out our 30 columns.
const schema = ... # array with field information

# For here on, it is just a bunch of macros performing named tuple 
transformations
let df = DF.fromText("test.csv")
   .map(schemaParser(schema, ";"))

# Projection can use whichever is shorter to type
df.map(t => t.projectAway(fields, to, remove))
df.map(t => t.projectTo(fields, to, keep))

# Adding new fields also does not require repeating existing fields
df.map(t => t.addFields(length: sqrt(t.x^2, t.y^2))

# Eventually even the schema of a join can be computed statically:
let joined = dfA.join(dfB, on=[joinField])


This should also play nicely with structural typing in Nim, e.g., passing data 
frames to functions can be done generically, and does not require to write out 
field names explicitly.

I'm not sure how this would work with objects. Since they are nominal, I guess 
they would have to be made explicitly available in the outer scope. Currently I 
leave it up to the user if they want to define their types explicitly, for 
instance via this macro:


type
  MyRowType = schemaType(schema)

proc myExplictlyTypedProc(df: DataFrame[MyRowType]) = ...


What I wanted to avoid is that a user has to explicitly name their types for 
each transformation.


Re: Nim core developer wanted

2017-02-23 Thread bluenote
That's really great news!

Do you already know when he will start and what will be the focus?


Re: Designing a data frame API

2017-02-21 Thread bluenote
@andrea: You are right, that is probably not yet very clear from the docs. They 
currently rely too much on being familiar with the concept of caching in 
frameworks like Spark (in fact, the API is modelled after Spark's 
[RDDs](https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.rdd.RDD),
 but for now without the distributed aspect).

The idea is basically to offer both lazy operations and eager operations. If 
your code looks like this


let df = DF.fromFile("data.csv").map(schemaParser, ',')
let averageAge = df.map(x => x.age).mean()
let maxHeight = df.map(x => x.height).max()
let longestName = df.map(x = x.name.len).max()


the operations are completely lazy, i.e., you would read the file three times 
from scratch, apply the parser each time, and continue with the respective 
operation. You would use this approach when your data is huge and it can't fit 
into memory entirely. This is obviously inefficient for small data which would 
fit into memory.

If you write the exact same code, but replace the first line by 


let df = DF.fromFile("data.csv").map(schemaParser, ',').cache()


the result of the mapping operation would be persisted in memory (using a 
`seq[T]` internally). Thus, all following operations will use the cache, and 
you would have to read and parse the file only once. Caching gives very good 
control over trading off memory usage over recomputation. You can cache the 
computation pipeline at any point, as long as you have the required memory. 
Typically you would use `cache` after having done some (potentially complex) 
computations which are required for multiple consecutive computations like 
repeated iteration in machine learning algorithms. In some use cases the data 
can also be preprocessed to make it fit into memory, e.g., by filtering to the 
interesting bits of the data, downsampling, or simply projecting the input data 
down to a single column.

Other differences to purely lazy libraries are that data frames require 
operations like sort or groupby, which require some sort of internal 
persistence. For now I'm just using an implementation which falls back on 
storing the entire data in memory, but I hope that I can add some spill-to-disk 
features later. 


Re: Designing a data frame API

2017-02-20 Thread bluenote
@chemist69: Thanks! And by the way, I forgot to mention the most important 
feature from a practical perspective: There already is a simple browser viewer 
available via `df.openInBrowser()`. No plotting yet, but at least handy for 
quick data inspection.

@jlp765: Handling different types is already possible, as illustrated in the 
readme example as well. The main difference between to dynamically typed APIs 
like Pandas is that you once have to tell the compiler about your schema -- but 
then you can fully benefit from type-safety in the processing pipeline. Let's 
say your CSV has columns _name_ (string), _age_ (int), _height_ (float), 
_birthday_ (date), then your code would look like this:


const schema = [
  col(StrCol, "name"),
  col(IntCol, "age"),
  col(FloatCol, "height"),
  col(DateCol, "birthday") # DateCol not yet implemented, but coming soon
]
let df = DF.fromText("data.csv.gz").map(schemaParser(schema, ','))


What happens here, is that the `schemaParser` macro builds a parser proc which 
takes a string as input and returns a named tuple of type `tuple[name: string, 
age: int64, height: float, birthday: SomeDateTimeTypeTBD]` (note that this 
allows to generate highly customized machine code, which is why the parser can 
be much faster than generic parsers). So yes, the data frame only holds a 
single type, but that type is heterogenous, and you can extract the individual 
"columns" back by e.g. `df.map(x => x.name)` giving you a `DataFrame[string]` 
instead of the full tuple.

Having to specify the schema might look tedious from a Pandas perspective. But 
the big benefit is that you can never get the column names or types wrong. In 
Pandas you see a lot of code which just says `def preprocess_data(df)`, and it 
is neither clear what `df` really contains nor what assumptions 
`preprocess_data` makes on the data. This can be solved by extensive 
documentation & testing, but is still difficult to maintain in big projects. 
With a type safe schema the assumptions about the data become explicit in the 
code, and the compiler can ensure that they are satisfied.

Global aggregation is already available. You could do for instance `df.map(x => 
x.age).mean()` to get the average age. There is also `reduce`/`fold`, which 
allows to implement custom aggregation functions. What's still missing is 
`groupBy` and `join`, but they are high priority for me as well, so I hope I 
can add them soon.


Re: Designing a data frame API

2017-02-19 Thread bluenote
@krux: Thanks for the feedback! I was thinking about your `dataLanguage` idea 
as well. But I don't know if this would allow good composability in larger 
projects, i.e., you want data frames to be something that can be passed around 
etc. What I can probably do in the end is to write a macro which takes the 
iteration body:


iterate(dataFrame):
  echo x


and the macro would analyze the processing pipeline and generate a single for 
loop internally. The good thing is that the user side of the API only exposes 
transformations and actions. So it doesn't really matter for now if I use 
closure iterators, and I can still switch the iteration logic internally later.

And the good news is that I get exceptionally good performance with the closure 
iterator approach already (I pushed a few first [benchmarks 
results](https://github.com/bluenote10/NimData#benchmarks)). I have optimized 
the CSV parsing macro a little bit, and CSV parsing is now a factor of 2 faster 
than Pandas, which is known to have a very fast parser. As expected for data 
which is still too small for Spark to shine, Nim is faster by a factor of 10 
(although Spark already runs on 4 cores).

I also made some good progress in terms of features and updated the 
documentation a lot, so this is reaching a state where it is actually pretty 
much usable.

@perturbation2: Yes very good point, and thanks for the link. If Nim will not 
feature multi dispatch this might become a problem. For now I don't need multi 
dispatch for the higher order functions like `map` though (and maybe I never 
will), so I will simply stick to using a proc (which I hope will continue to 
work).

I also understand issue 3 now, for the record: The compiler is basically 
complaining that the base method has a provable lock level of 0, while one of 
the overloaded methods calls a procvar, and potentially, this procvar can lock. 
The locking system needs to know lock levels at compile time though, which is 
ruined by the dynamic dispatching in this case. There are two ways out: 
Convince the compiler that the procvar does not lock, or tell the compiler in 
the base method that there will be overloads of unknown lock level. The former 
would be nicer, but I can't really get it to work for now -- for the latter I 
have opened a tiny PR to allow doing that in Nim.


Re: Function v. Writing operations

2017-02-19 Thread bluenote
That doesn't really make sense. The for loop itself increments the variable. 
You can't increment it because it is immutable. And you need a colon and a 
lower bound.


Re: Documentation for structures created with macros

2017-02-19 Thread bluenote
If I remember correctly the difference between generating docs with either `nim 
doc ` or `nim doc2 ` is that the latter includes stuff from 
macros. A quick check seems to confirm this:


import macros

macro test(): untyped =
  let testproc = quote do:
proc someProc*(param1: int) =
  ## Documentation here
  echo "test"
  echo testproc.treerepr
  result = testproc

test()


Note that the macros module documentation mentions that the content of comments 
is not yet part of the AST (it appears as a `nnkCommentStmt` as the very first 
element of the body). But apparently that is not an issue, because it can be 
created from quote (or a template + getAst probably). 


Designing a data frame API

2017-02-12 Thread bluenote
I finally found some time to work on something I wanted to start immediately 
when I discovered Nim: A data frame API allowing lazy out-of-core data 
analytics. You can find a first working prototype over at GitHub (under the 
uninspired name [NimData](https://github.com/bluenote10/NimData)). So far I'm 
pretty happy with what is possible already now. In fact I got carried away a 
little bit when creating the readme example based on this Bundesliga data set .

Quick motivation: The project is targeted between the worlds of Pandas/R and 
map-reduce successors like Spark/Flink. In the Pandas/R world, the general 
assumption is that your data fits into memory, and things get awkward when the 
data size exceeds this threshold. Spark/Flink offer a different API design, 
which makes distributed out-of-core processing easier, and many companies are 
moving in this direction now. However, this can be a heavy investment because 
Spark/Flink basically require that you build and operate a cluster (=> 
costly/complicated) -- the performance of running in local mode is often not so 
great (partly due to required abstractions + JVM). NimData uses a very similar 
API design allowing out-of-core processing, but for the time being, the focus 
is just on running locally. In other words, the target is "medium" sized data, 
i.e., data which may not fit into memory entirely, but does not justify to 
invest in a cluster. I haven't started benchmarking yet, but I could imagine 
that Nim's native speed might even keep up with a small cluster for certain 
problems.

In terms of the design I'm at a point where I could use some help from the Nim 
veterans to verify if this is a good path. I went for a design based on dynamic 
dispatching, and I was facing some of problems related to both method dispatch 
and iterators. The biggest showstopper was that I could not mix generic and 
specific methods (which didn't allow to actually read from files ), but then I 
found the work-around documented in 
[#5325](https://github.com/nim-lang/Nim/issues/5325). But there are still some 
issues left, and I'm not sure if they are either a mistake on my part or a 
known/unknown Nim issue. Some of the issues are tricky, because they disappear 
in isolated examples. I have prepared the following minimal example which 
illustrates both the general design and the outstanding issues:


import times
import typetraits
import strutils
import sequtils
import future
import macros

type
  DataFrame[T] = ref object of RootObj
  
  CachedDataFrame[T] = ref object of DataFrame[T]
data: seq[T]
  
  MappedDataFrame[U, T] = ref object of DataFrame[T]
orig: DataFrame[U]
f: proc(x: U): T
  
  FilteredDataFrame[T] = ref object of DataFrame[T]
orig: DataFrame[T]
f: proc(x: T): bool

proc newCachedDataFrame[T](data: seq[T]): DataFrame[T] =
  result = CachedDataFrame[T](data: data)

# 
-
# Transformations
# 
-

# Issue 1: I'm getting a deprecation warning for this function:
#   `Warning: generic method not attachable to object type is deprecated`
# I don't understand why it is not attachable, T and U are both unambiguous
# from the mapping proc. Is this a showstopper, because it will break
# in a future version of Nim?
method map[U, T](df: DataFrame[U], f: proc(x: U): T): DataFrame[T] {.base.} 
=
  result = MappedDataFrame[U, T](orig: df, f: f)

method filter[T](df: DataFrame[T], f: proc(x: T): bool): DataFrame[T] 
{.base.} =
  result = FilteredDataFrame[T](orig: df, f: f)

# 
-
# Iterators
# 
-

# Issue 2: I don't understand why this dummy wrapper is required below.
# In the `for x in ...` lines below I was trying two variants:
#
# - `for x in it:` This gives a compilation error:
#   `Error: type mismatch: got (iterator (): int{.closure.})`
#   which is surprising because that is exactly the type required, isn't it?
# - `for x in it():` This compiles, but it leads to bugs!
#   When chaining e.g. two `map` calls the resulting iterator will
#   just return zero elements, irrespective of what the original
#   iterator is.
#
# For some strange reason converting the closure iterator to an inline
# iterator can serve as a work around.
iterator toIterBugfix[T](closureIt: iterator(): T): T {.inline.} =
  for x in closureIt():
yield x

method iter[T](df: DataFrame[T]): (iterator(): T) {.base.} =
  quit "base method called (DataFrame.iter)"

method iter[T](df: CachedDataFrame[T]): (iterator(): T) =
 

Re: Portaudio example doesn't work with threads:on

2017-02-12 Thread bluenote
Maybe not the most helpful comment, but I can confirm that this works without 
problems on Linux. I only have to increase the buffer size to avoid underruns 
-- but has nothing to do with threads:on. In a more complex scenario, it's 
important to call `system.setupForeignGc()` at the top of the callback to get 
proper GC. But the saw_out example does not require GC in the callback, so 
won't help either.

To track down the problem it would be interesting to build a minimal C example 
which sets up a p-thread like portaudio does, and calls a callback. If this 
minimal example fails as well, we would at least have something clear to work 
on (=> issue tracker).


Re: How to compile a shared library for JNI?

2017-01-06 Thread bluenote
Yes, the traceback from within SBT indeed looks strange. To some degree this is 
a result of the forked VM. When running standalone or also with the pure Java 
example, there is no Java traceback at all, because the JVM segfaults straight 
away.

I was just stumbling over [this 
comment](http://stackoverflow.com/a/28445066/1804173):

> There is one catchy situation in JNI code: when such a code blocks SIGSEGV 
> signal e.g. because it blocks all signals (quite common approach in threaded 
> C code how to ensure that only main thread will process signals) AND it calls 
> 'back' Java VM (aka callback) then it can result in quite random 
> SIGSEGV-triggered aborting of the process. And there is virtually nothing 
> wrong - SIGSEGV is actually triggered by Java VM in order to detect certain 
> conditions in memory (it acts as memory barrier … etc) and it expects that 
> such a signal will be handled by Java VM. Unfortunately when SIGSEGV is 
> blocked, then 'standard' SIGSEGV reaction is triggered => VM process crashes.

I have no idea how signal handling works in detail and will have to read up on 
it, but maybe something along the lines: The JVM trying to "communicate memory 
barriers via SIGSEGV" (wtf?) and the Nim signal handler catching it. Is there 
an easy way to test this? Like disabling Nim's signal handler altogether?


Re: How to compile a shared library for JNI?

2017-01-04 Thread bluenote
I'm on Ubuntu 14.04, but with a more recent JVM (1.8.0_74-b02). Nim version is 
the last tagged release 0.15.2.

Regarding the repeating: You could simply use that other `run.sh` script and 
replace the java command by `sbt run`. Or if you want to avoid the load up 
time: Add `addSbtPlugin("com.github.tkawachi" % "sbt-repeat" % "0.0.1")` to the 
`project/plugins.sbt` and use `repeat 100 run` in the SBT shell.


Re: better example code for tutorial partI Iterators

2017-01-04 Thread bluenote
You can:

  * Fork the Nim repository on Github: 
[https://github.com/nim-lang/Nim](https://github.com/nim-lang/Nim)
  * Edit the file doc/tut1.rst to your liking
  * Use "create pull request" to contribute your modification




Re: How to compile a shared library for JNI?

2017-01-04 Thread bluenote
It varies a lot: When running the Scala example from the SBT shell it is maybe 
1 out of 5. For the Java example on the debug branch I'm using the `run.sh` 
which simply performs 1000 iterations and terminates on a crash. I'm usually 
crashing within <200 iterations, sometimes in the first 10, max was maybe 400.

When replacing the .so by the plain C library I'm reaching 1000 iterations 
without a crash. But I'm still not sure if it may be a JVM bug, which is only 
triggered by something in the Nim implementation because:

  * The traceback always points to `VM_Version::get_processor_features()` \-- 
with true stack corruption you would expect more random tracebacks, right?
  * When running a longer computation on Nim side, the crash always seems to 
happen after the function has returned.




Re: How to compile a shared library for JNI?

2017-01-04 Thread bluenote
Good idea to emit `NimMain();`, but unfortunately it still crashes. I was 
wondering if it is due to either the function signature or maybe the `printf`. 
But using exactly your function does also crash (with a lower probability 
though, requires >> 100 iterations).


Re: How to compile a shared library for JNI?

2017-01-04 Thread bluenote
@Krux02: Everything prepared here: 
[https://github.com/bluenote10/JniScalaNimExample](https://github.com/bluenote10/JniScalaNimExample)

The master branch contains a SBT + Scala setup, including a customized build 
task (coupled to "compile") and source monitoring so that ~test / ~compile / 
~run are fully functional. The debug branch is the minimal example (in Java for 
better reproducibility) which does segfault for me. But for instance @yglukhov 
already confirmed that he is not getting segfaults on MacOS with this example.

@Araq: That was also a suggestion by @yglukhov, but unfortunately it also 
crashes. Any pointers in which direction you would continue testing?


Re: How to compile a shared library for JNI?

2017-01-03 Thread bluenote
Actually I was doing that, I only made a mistake simplifying the problem for 
demonstration purposes. On the master branch I have set up the whole SBT tool 
chain using the sbt-jni plugin, which comes with a javah interface for Scala. 
In my original version I obtained the correct signature from that. By the way, 
I'm actually pretty happy how well Nim integrates with the Scala+SBT world.

I just verified: Using the correct for the simplified example does not make a 
difference.