HN user

jboy

346 karma

Co-founder of ObjectAI.com

Co-creator of Pymod: https://github.com/jboy/nim-pymod

Posts10
Comments87
View on HN

He seems to be operating under 3 main delusions (with a healthy dose of caste-related inferiority complex mixed in):

1. Confusion about the differences (or even the fact that they are different) between copyright, trademark, and patent. He copyrighted some software called "EMAIL", which anyone could do. That doesn't give him any ownership of the term "email" (as a trademark would), nor does it register him as the inventor in any way (as a patent would).

2. A belief that being (maybe) the first to name something X makes him the inventor of X. (At best, he could possibly be described as "one of the first to coin the term 'email'.")

3. A belief that naming something X subsequently defines what X is. Hence, he disregards all predecessors as "not X because they are not exactly the same as what I called X".

Over time, his caste-related inferiority complex seems to have evolved into a strong mistrust of recognised authority ("What does Vint Cerf know?") and then further into a conspiracy about the "military-industrial complex".

He seems more sadly deluded than an intentional charlatan.

Even though I don't like Go's explicit error handling, I think this is a very reasonable comment.

I don't like Go's explicit error handling because (1) I think it clutters up your main code path with error-handling logic, and (2) it forces you to always handle errors locally (even if that local code does not have the context to know how to handle the error) or return the error code through multiple layers of functions (back to where it can be handled).

That said, I completely agree that exceptions are also problematic. As you say, you can never really be sure of what exceptions can be thrown. Some languages have a "throw" keyword, in which you're meant to enumerate the list of possible exceptions; but of course, that's a headache to maintain, and is affected by inner code (such as library code) that might be completely out of your control or review. And when should the "throw" keyword be enforced, at compile time or runtime? And what should happen if the "throw" keyword's list of possible exceptions is violated?

Then of course there is the other problem with exceptions, the flip-side to being forced to handle an error locally: As your exception unwinds the stack, it might obliterate some local context that is needed to decide how to handle the error; or it might obliterate some local context that is needed to continue with your original task after the error has been handled!

The most interesting (and least broken) error-handling mechanism I've encountered is Common Lisp's "condition" system: http://www.gigamonkeys.com/book/beyond-exception-handling-co...

I see C++'s `std::set_new_handler` function [0] as C++'s less-capable equivalent to Lisp condition handlers. But the function invoked by `std::set_new_handler` lacks the ability to assess local context to decide how to handle the problem.

[0] http://www.cplusplus.com/reference/new/set_new_handler/

EDIT: I would love to see a language like Nim incorporate something like Lisp's condition system. Nim already offers "procedural types" (function pointers) [1] and closures [2] to capture variables from the enclosing scope. Nim even offers "anonymous procs" [3], to avoid the need to define new error-handling functions everywhere.

[1] https://nim-lang.org/docs/manual.html#types-procedural-type

[2] https://nim-lang.org/docs/manual.html#procedures-closures

[3] https://nim-lang.org/docs/manual.html#procedures-anonymous-p...

I've never used the JS backend or C++ backend, so I can only talk about the C backend.

With the C backend, the Nim code is transpiled to C code (surprisingly readable C code, as far as auto-generated C goes), which is then compiled to one of: a binary executable, a shared C library, or a static C library: https://nim-lang.org/docs/nimc.html#compiler-usage

In fact, Nim-Pymod relies upon the Nim->C->library compilation, because it uses the Python C API to produce Python extension modules: https://docs.python.org/2/extending/extending.html , https://docs.python.org/2/c-api/

If you want to see a shared C library produced by Nim, have a play with some of the examples provided with Nim-Pymod: https://github.com/jboy/nim-pymod/tree/master/examples It auto-generates the appropriate Python C API boilerplate functions around your Nim functions, then compiles the whole thing as a shared C library, exposing the auto-generated functions in the shared library.

Regarding runtime type-checking: Again, I can only talk about the C backend. The type checking provided by shared or static C libraries will be whatever the C compiler enforces... I haven't tested whether (or how much) this can be violated.

Nim-Pymod does auto-generate the Python->C type-checking code for you, so you can't (for example) pass in a Python string when an int is expected by your Nim function.

Nice work! My startup http://objectai.com/ has just launched something similar, Pizza Photo Editor: https://pizza.pics/

Pizza Photo Editor is still early-stage -- we're still adding features and increasing the coverage of different object classes in our training data set -- but the core tech is there, and it does have an interactive web UI, so it's already fun to play with. :)

Looking at the example inputs & outputs for ObjectCropBot, it's evident that the challenge is not just detecting the object and clipping it approximately, but tracing a tight precise boundary around it. We've found that DNN/ConvNet-based approaches don't offer the necessary precision, so it's necessary to perform some pre- or post-processing using other Computer Vision techniques. At Object AI, we've developed an "object boundary deduction" pipeline that combines ConvNets with other tech. It's interesting that the blog post that you've linked to makes the same observation!

I write my Nim code in Vim. I've never had any problems with auto-suggests.

My Vim config for Nim can be found here: https://github.com/jboy/dotfiles/tree/master/vim (based upon https://github.com/zah/nim.vim , with a few improvements to my taste).

In particular, Vim syntax highlighting for Nim: https://github.com/jboy/dotfiles/blob/master/vim/syntax/nim.... and some convenient Vim mappings to jump around in Nim: https://github.com/jboy/dotfiles/tree/master/vim/ftplugin/ni...

I also use (and recommend) the CamelCaseMode Vim plugin with Python & Nim.

Yes, my startup Object AI uses Nim code in production. We have in-house implementations of machine learning, computer vision & image processing code in Nim, using a library called "Nim-Pymod" to integrate with Python's Numpy: https://github.com/jboy/nim-pymod

(As you can see, I was one of the authors of that library in a previous startup. We haven't worked on Nim-Pymod in a while, alas -- I've been focused on the new startup! -- but Nim-Pymod is sufficient for our needs right now.)

Our webserver main-loops are in Python; our number-crunching ML/CV/img-proc code is Python extension modules written in Nim.

As a C++ & Python programmer, I'm a huge fan of Nim, which to me combines the best of both languages (such as Python's clear, concise syntax & built-in collection types, with C++'s powerful generics & zero-cost abstractions), with some treats from other languages mixed in (such as Lisp-like macros and some Ruby-like syntax). I find Nim much more readable than C or C++, especially for Numpy integration. I also find Nim much more efficient to code in than C or C++ (in terms of programmer time).

And Nim is a very extensible language, which enables Nim-Pymod to be more than just a wrapper. For example:

1. Nim-Pymod uses Nim macros (which are like optionally-typed Lisp macros rather than text-munging C preprocessor macros) to auto-generate the C boilerplate functions around our Nim code to create Python extension modules.

2. Nim-Pymod provides statically-typed C++-like iterators to access the Numpy arrays; these iterators include automatic inline checks to catch the usual subtle array-access errors. Nim macros are themselves Nim code, which can be controlled via globals, which in turn can be set by compiler directives; by compiling the Nim code in "production" mode rather than "debug" mode after testing, we can switch off the slowest of these checks to get back to direct-access speed without needing to make any code changes. (And of course Nim's static typing catches type errors at compilation time regardless of the compilation mode.)

3. Nim exceptions have an informative stack trace like Python exceptions do, and Nim-Pymod converts Nim exceptions into Python exceptions at the interface, preserving the stack trace, meaning you have a Python stack trace all the way back to the exact location in your Nim code.

Earlier on in our development of Nim-Pymod, there were some occasional headaches with Nim due to its in-development status. Occasionally the Nim syntax would change slightly and that would break our code (boo). We've also debugged a few problems in the Nim standard library. I suppose these problems are an unfortunate consequence of Nim having a small set of core devs contributing their time (rather than being supported by Microsoft, Sun, Google or Mozilla). Fortunately, these problems seem to have stabilised by now.

The Nim standard library is reasonably large, somewhere between C++ STL (data structures & algos) & Python stdlib (task-specific functionality). I recall that the stdlib could use some standardisation for uniformity, but I haven't been watching it closely for the last year or so.

Third party libraries are not abundant, aside from a handful of prolific Nim community-members who have produced dozens of fantastic libraries (eg, https://github.com/def- , https://github.com/dom96 , https://github.com/fowlmouth , https://github.com/yglukhov ).

I'm happy to answer any other questions about using Nim in production!

I think the parent's point was about whether the AlphaGo AI can generalize to a different board size (as a human player presumably can) rather than about what is the normal Go board size, or what board sizes are easier or harder.

The parent was suggesting that while a human might possess a general understanding of Go, performing comparably regardless of board size ("The human would play on the same level"), the AlphaGo AI in contrast might drop significantly in capability on a board of different size. In effect, the AlphaGo AI might just be a very well-fitted (perhaps even overfitted) machine-learned algorithm on a 19x19 board, lacking a fundamental "understanding" of the game that could generalize to a different board size.

Hi Marcus, have you ever taken a look at Nim? It's quite similar to Swift in several respects, but it has a primarily Python-like syntax (including indentation by blocks rather than braces) with bits of Ruby & others mixed in.

Useful links: http://nim-lang.org/ , http://nim-lang.org/docs/tut1.html , https://nim-by-example.github.io/ , http://nim-lang.org/docs/manual.html

At work, we use Python as our interpreted language & Nim as our fast, strongly-typed, compiled language. We created Nim-Pymod to enable Nim code to be compiled into Python modules: https://github.com/jboy/nim-pymod

There's also a web-framework in Nim called Jester, which describes itself as "a Sinatra-like web framework": https://github.com/dom96/jester

Quite possibly! That's the extra dimension added to the experiment. :)

It would be even more fascinating if you could cluster facial expressions or motions as "more female" or "more male". And for bonus points, work out a way to "filter" or "smooth" the facial signal to reduce/remove these giveaway hints (or insert false hints).

I think it would be amazing if they could combine this voice-modulation technology with a facial motion capture technology (like in Avatar) to display artificial/shifting faces as well as voices. You could effectively create a computer screen-based version of the "scramble suit" used in A Scanner Darkly! http://www.imdb.com/title/tt0405296/mediaviewer/rm1872861440

I think a combined face+voice system would be even more useful in interviews (since a significant amount of human communication is expressed through facial cues). It would also add another dimension to your proposed voice-modulation gender-blinding experiment.

There were two particular points in the article that strongly resonated with me:

But the problem is not confined to referendums: in an election, you may cast your vote, but you are also casting it away for the next few years. This system of delegation to an elected representative may have been necessary in the past – when communication was slow and information was limited – but it is completely out of touch with the way citizens interact with each other today.

This sounds very much like an area of human communication in need of a technological update. (And I'm not talking about using insecure/rigged voting machines at elections.) I'm not confident that more frequent referenda is the answer (a monthly Brexit/Nobrexit doesn't sound like the best idea for a number of reasons), but surely there's some way to decrease the political communication/feedback latency.

But the real insight for me was this quote from British sociologist Colin Crouch:

public electoral debate is a tightly controlled spectacle, managed by rival teams of professionals expert in the techniques of persuasion, and considering a small range of issues selected by those teams. The mass of citizens plays a passive, quiescent part, responding only to the signals given them.

There is a double-dissolution (ie, all seats in both houses of parliament are up for re-election) federal election in Australia happening this weekend, and the electioneering over the past few months has been exactly as Mr Crouch described: The leaders of the two major parties have chosen a few uncontroversial campaign issues that fail to address any of the real problems (rising socioeconomic inequality, a vocal minority undercurrent of racial/religious tension & bigotry) in Australia. All the leaders will discuss during their campaigns are these superficial issues. The people are simply expected to react to these few selected issues, agreeing or disagreeing as appropriate for their political party affiliation, without asking for any discussion of broader/deeper issues.

There are a few minor parties & independents that are attempting to broaden the discussion, but the two major parties are openly advising voters to vote "for stability" (ie, them) rather than "instability" that might result in a minority government.

Agreed about using intermediate variables.

What's better than comments to describe what the code does? CODE that describes what the code does. (Let the code describe WHAT the code does, and if necessary, the comments describe WHY the code does it like that.)

In C++, if I use an intermediate variable to decompose a complicated expression into easier-to-understand sub-expressions, I like to make the intermediate variable `const` to emphasize that it's an intermediate component.

"Sometimes you must bow to existing convention" is indeed a reasonable point, so I suppose I should clarify/refine my position.

If you're implementing an STL-like container in C++, then absolutely -- you should stick with the convention: `empty`, `clear`, `size`, etc. To deviate from that convention would be an exercise in confusing the users of your code. You should make a note in the class comment that it deviates from any other project-wide naming scheme because it conforms to the STL container interface, and move on.

But if you're creating a C++ class that is NOT intended to be an STL-like container (or if you're not working in C++!), then I'd argue that it would be better to go with `is_empty` & `make_empty` (if you're applying this prefix naming scheme across the rest of your codebase) for the benefits I've described above.

Some C++ programmers, perhaps. But I've just explained why `empty` & `clear` are ambiguous. Even if `empty` & `clear` can never be removed from the STL containers, there's no requirement that these ambiguous names must be propagated to new code.

But focusing exclusively on these two names is missing the forest for the trees. These two names are just a particularly striking example that illustrates the benefit of prefixes. A codebase that applies useful prefix naming will be an easier codebase to understand.

And applying prefix naming consistently will also make it easier for a new developer to contribute to a codebase, since there will be no ambiguity about what to name new functions, nor what to expect them to be named. `is_empty` & `make_empty` would simply be part of that consistency.

This article is a good start, but I found it much too light on detail. Each section ended just when I was ready for it to dive into details! For example, in the final section "Make it easy to digest":

Using prefixes in names is a great way to add meaning to them. It’s a practice that used to be popular, and I think misuse is the reason it hasn’t kept up. Prefix systems like hungarian notation were initially meant to add meaning, but with time they ended up being used in less contextual ways, such as just to add type information.

OK, great, I agree -- but what are some suggestions/examples of good prefixes? What are some examples of bad prefixes that we should avoid?

To illustrate the sort of detail I'd like to read, here is an example of my own of good/bad method names that would be greatly improved by judicious use of prefixes.

My standard go-to example for ambiguous naming is the std::vector in the C++ STL. There is a member function `vec.empty()`: Does this function empty the vector [Y/N]? Answer: No, it doesn't. To do that, you instead use the member function `vec.clear()`. There is no logic a priori to know the difference between `empty` & `clear`, nor what operation either performs if you see it in isolation. You must simply memorize the meanings, or consult the docs every time.

In the C++ style guides I've written, I've always encouraged the prefixing of member function names with a verb. Boolean accessors should be prefixed with `is-`. The only exception should be non-boolean accessors such as `size` (which has its own problems as a name). Forcing non-boolean accessors to be preceded by a verb invariably results in names like `getSize()`, where `get-` adds no useful information, clashes with the standard C++ naming style for accessors, and really just clutters the code with visual noise.

Using these prefixes: (depending upon your project's preference for underscores or CamelCase)

  .empty -> .isEmpty() or .is_empty()
  .clear -> .makeEmpty() or .make_empty()
As an additional benefit, the use of disambiguating prefixes also enables the interface designer to standardize upon a single term "empty" to describe the state of containing no elements in the vector, rather than playing the synonym game ("empty", "clear", etc.). The programmer should not need to wonder whether "clear" empties a vector in a different way.

Hi Andrea, as always, I'm very impressed by the diversity of high-quality, useful Nim projects you produce. :)

I agree with the other posters that the multi-line [ ] syntax is not very beautiful or Nim-idiomatic. As @Nycto suggests, nested code blocks would seem more Nim-idiomatic.

Also, I haven't seen anywhere else in Nim stdlib where multi-line [ ] expressions are used. In my mental model of Nim, [ ] is for 4 uses: 1. generics, 2. tuples/subranges, 3. array literals, and 4. array indexing. And none of these scenarios contain nested code blocks inside them.

For nesting of routes I would find nested code blocks most idiomatic. Or, if you find that nested code blocks simply do not work well, the key-value idiom of a table constructor {k:v} seems more idiomatic than [ ]: http://nim-lang.org/docs/manual.html#statements-and-expressi...

If it compiles (I admit I haven't tested it -- this is just off the top of my head), you could perhaps use a syntax something like:

  get {
    path("/api/status"): ok(getStatus()),
    pathChunk("/api/message"): # etc.
  }
Since the order of the (key,value)-pairs is preserved, this would automatically handle the ordered composition `h1 ~ h2`.

Hey, I did something similar about 12 years ago!

I'd tried the Dvorak keyboard layout and found that I liked the guiding design principles, but decided that the actual layout was a sub-optimal implementation of those design principles. So, I dumped several megs of personal email archives (with the headers & '>' removed) and several megs of C++/Python source code (including comments) through some little statistical number-crunching programs I had written, to analyse:

* key frequency (I still recall that the top 7 were ETOAINS)

* 2-key combination frequencies (for example: TH, SH, ST, NT, EA, OU, IE, etc)

I also wanted it to be Vim-friendly, C++-friendly & UNIX command-line-friendly where this didn't degrade the effectiveness for general English language.

My best layout (which I've been using as my keyboard layout for the last 12 years, thank you Xmodmap on Linux) is:

  QYOU,  XRDCW
  PIEA.  VHTSN
  K;JG_  ZLBFM
Because it was significantly inspired by ideas from the Dvorak keyboard layout (and because I was such a modest young fellow), I called it the "Boyden keyboard layout". :P

Just as you did, I came to some specific conclusions about comfortable layout:

* E & T must be under the middle fingers on the home row.

* T & H need to be adjacent.

* Vowels on one side, most important consonants on the other.

In an important contrast to your layout, I optimised for rolling fingers inwards. This is something I learned from the Dvorak layout: It's easier to drum your fingers by rolling inwards rather than rolling outwards. This is why I have "IEA" on the left in contrast to your "AEI", and "HTSN" on the right in contrast to your "NTHS". (It's actually quite striking how similar our home rows are.) Similarly, I have "YOU," on the upper left, in contrast to your ",UYP".

[Interestingly, the Workman layout lays out SH & ST for inwards finger rolls, but does not lay out TH for an inwards finger roll. I consider this a failing of the Workman layout.]

Another principle that I borrowed from the Dvorak layout is that the most agile fingers in order are: middle, first, ring, pinkie. So, I tried to avoid adjacent double-use of the same finger; but when double-use is necessary, prefer to do it with one of the first two fingers.

I also tweaked the layout for Bash shell a little: My most frequently-used command is `cd`, so these two letters are adjacent. Also, '.' is frequently doubled in directory paths (".."), so that's a first-finger key. It also makes sense to have '.' & ',' as middle-column first-finger keys, because they usually occur at the ends of words in prose (that is, at the end of an inward finger roll), and words almost never end in A or U in English.

For anyone unfamiliar with Nim, I'll give a quick summary of Nim generics, templates & macros, in terms of C, C++, Java & Lisp:

* Nim generics = parametrization-by-type of procs (functions) or other type definitions. Happens at compile time. Like Java generics or C++ templates, except that it uses [ ] rather than < >.

* Nim templates = direct textual substitution of code at the call-site at compile-time, like the C preprocessor, except that: 1. It operates upon a parsed Nim AST rather than plain-text code; 2. It's (by default) hygenic; and 3. The syntax is the same as regular Nim language syntax (in contrast to the crippled C preprocessor syntax).

* Nim macros = compile-time evaluation of code to perform side-effects, one of which may be inserting new code at the call-site. Nim macros are most like Lisp macros. An invoked Nim macro receives a parsed Nim AST as a tree data-structure, and is able to traverse & manipulate that AST, or create & output a new AST. When evaluating macros, the Nim compiler runs the macro code in a compile-time Nim interpreter, so macros can invoke any other functions, allocate data-structures, etc. And again, the syntax is the same as regular Nim language syntax.

[There's another Nim language feature that I really like, which I think is worth mentioning here: the `const` keyword, to define constants. Nim provides `var` to define variables that are read-write storage boxes, and `let` for single-assignment storage boxes. `const` is like `let`, except it's evaluated at compile time. This means you can evaluate arbitrarily-complicated expressions (including function calls) at compile time, obtaining the result as a constant of the appropriate result type, which can then be inlined at all usage-sites -- just as if you'd entered the literal value directly in your code.]

With this background in place, I can finally get to my main point:

When I'm getting excited about Nim to friends, I tell them that I think Nim macros are the best tradeoff between an expressive Python-like syntax & powerful AST-based, Lisp-like macros.

You see, no-one would dispute that it is very elegant to use regular function syntax to operate upon homoiconic code as a data-structure. And no-one would dispute that operating upon a pre-parsed AST is superior to crude text-concatenation (like in the C preprocessor). But as a commenter on HN pointed out in a recent thread about Lisp:

"""So, the real question is why did such a magical language lose to the upstarts that all appeared in the late 80's and early 90's: Perl, Python, Tcl, Lua, etc. Answer: files, strings, and hash tables. All of those languages make mangling text pathetically easy. Perl is obviously the poster-child for one-liners, but all of those make that task pretty darn easy. Lisp makes those tasks really annoying. Just take a look at the Common Lisp Cookbook for strings: http://cl-cookbook.sourceforge.net/strings.html """ -- https://news.ycombinator.com/item?id=11700176

Dense language syntax is beneficial because it enables brevity for frequently-occurring operations. For example: string indexing, slicing & especially regex matching, if you do a lot of text-processing; inline arithmetic operators if you do a lot of arithmetic; and array operators, if you do a lot of matrix processing.

Nim's macros combine a dense (Python-like) language syntax with powerful AST-based macros, enabling you to traverse & manipulate the AST just like any other data-structure.

Vesting is absolutely not implied, expected, or required by the law. Regardless of common practice in YC companies or YC applications, vesting is not the automatic default mode in corporation law or contract law.

If there is evidence of an agreement (whether written or oral) between the parties to apply a vesting schedule, then that will override the default mode; otherwise the default mode (no vesting) prevails.

OK firstly, consideration doesn't have to be "valuable". It has to have _nonzero_ value, but that value can famously be as trivial as "a mere peppercorn" [0]. Furthermore: "a peppercorn does not cease to be good consideration if it is established that the promisee does not like pepper and will throw away the corn".

[0] https://en.wikipedia.org/wiki/Peppercorn_(legal)

The point is that the law doesn't attempt to make everyone "be nice", nor does it protect you from making a bad business decision. It's really just ensuring that there was _some_ business (ie, some exchange of nonzero value) occurring at all.

Secondly, it's important to note that a written contract is not absolutely needed to enact shared ownership; a written contract (or a deed, or a shareholder's agreement) is just to formalize the agreement in writing to avoid disagreement later.

If you start working together, shared ownership is the _default_ in the absence of any mode-changing agreements. Were they working together? A recorded video, in which they take turns looking into the camera and effectively saying "We are working together" [1] is a pretty strong evidence that, at one point, they were working together.

[1] https://m.youtube.com/watch?v=_P6oXe1YI90

Thirdly, in the absence of formal documents saying "We are officially working together" or "We are officially not working together", the court has to fall back on attempting to determine the intention. It will have to fall back on looking for any evidence (like that video) that suggests they were in agreement about working together at some point.

For anyone who's interested in learning more about Nim, here is Andreas Rumpf (the creator of Nim)'s talk at the OSCON 2015 conference: https://www.youtube.com/watch?v=4rJEBs_Nnaw ; and here's a longer, more-technical talk at the first Nim Workshop in November 2015: https://www.youtube.com/watch?v=zb3Sqs7lNJo

Here's the official Nim tutorial: http://nim-lang.org/docs/tut1.html

And here is the very approachable "Nim by Example", which offers a series of short, simple lessons about the main Nim features: https://nim-by-example.github.io/

You might also be interested to check out Nim. It transpiles to C before invoking the C compiler, so it runs as fast as C++ and has excellent C-compatibility (and by extension, excellent C++-compatibility).

Compiling a shared library is as easy as passing the "--app:lib" option to the Nim compiler: http://nim-lang.org/docs/nimc.html#compiler-usage-command-li...

The GC is optional; you can manage your memory manually if you prefer: http://nim-lang.org/docs/manual.html#types-reference-and-poi...

The Nim tutorial is here if you want to have a quick skim: http://nim-lang.org/docs/tut1.html

Hi, the short answer is "Yes, but ...".

Yes, Pymod's PyArrayObject can be created & accessed entirely in Nim; yes, its length (actually, shape) is specified at runtime; and yes, it can be resized after creation.

However, Pymod's PyArrayObject is designed for maximum binary compatibility with Numpy. As such:

1. It uses Numpy's array creation functions (such as `createSimpleNew`), which in turn uses the Python runtime memory allocator. So at the very least, Pymod assumes you've linked against `-lpythonX.Y`.

2. It integrates with Python's GC rather than Nim's GC. (This is why it's passed around as `ptr PyArrayObject` rather than `ref PyArrayObject` -- it's untouchable by the Nim GC, but instead uses Python refcounts.)

Of course, we do intend to extend Pymod to include a pure-Nim sibling for PyArrayObject, but it doesn't exist yet.

If you want a high-quality no-Python-dependency VLA in Nim right now, I'd recommend this library by Andrea Ferretti [ https://github.com/unicredit/linear-algebra ]. It can link against your system BLAS, in addition to offering GPU support using NVIDIA CUDA. Andrea is another member of the Nim community who does a lot of scientific computing: http://rnduja.github.io/2015/10/21/scientific-nim/