Re: Language Design Question: Backend C vs LLVM IR
> In a nutshell, how does newruntime make the GC obsolete? The basic idea was sketched here: [https://nim-lang.org/araq/ownedrefs.html](https://nim-lang.org/araq/ownedrefs.html) but it has been revised a few times. For the most important Nim data structures like strings and seqs it seems to work fine, so that many Nim programs just will not need the GC. And other programs, maybe with very complicated data structures, can continue using the old runtime with one of the provided GCs. cumulonimbus gave you the link to Nim's LLVM backend, it has some restrictions currently.
Re: Help getting this macro to work in a for loop
Thank you! That was a very good explanation; it now helps me understand why macros cannot work in for loops.
Re: Help getting this macro to work in a for loop
Thank you! I am a real beginner in Nim macros. Your example snippet will serve really helpful to me as I am learning this more. \--- I'd also like to thank @JasperJenkins (from Gitter) for offering his solution to this problem on IRC here: [https://irclogs.nim-lang.org/14-06-2019.html#18:34:24](https://irclogs.nim-lang.org/14-06-2019.html#18:34:24) Here's the Nim playground link he shared: [https://play.nim-lang.org/index.html?ix=1LMY](https://play.nim-lang.org/index.html?ix=1LMY) For convenience, that solution is inlined below: import macros {.experimental: "forLoopMacros".} type Obj = object a, b, c: int proc replace(n: NimNode, symbolic, real: NimNode): NimNode = if n.kind == nnkIdent and n.eqIdent(symbolic): # this identifier is the for loop variable: return a real field ident instead return real else: result = n # return unchanged verbatim # continure recursion on children for i in 0 ..< n.len: n[i] = replace(n[i], symbolic, real) macro replaceField(forLoop: ForLoopStmt): untyped = echo "\nCode before:\n", toStrLit(forLoop).strVal result = newTree(nnkStmtList) let forVar = forLoop[0] # k fields = forLoop[1][1] # ["a", "b", "c"] stmts = forLoop[2] # loop body for f in fields: # Copy the loop body since the loop gets unrolled. # We need a block so any variables don't collide. let stmtsCopy = newBlockStmt(copyNimTree(stmts)) # recursively replace the forVar with a new identifer. result.add(replace( stmtsCopy, # this fields copy of the stmts forVar, # identifier to replace ident(f.strVal))) # new identifer made from one of the real obj fields echo "\nCode after:", toStrLit(result).strVal, "\n" var obj = Obj(a: 1, b: 2, c: 3) echo obj for k in replaceField(["a", "b", "c"]): # more elaborate example that would fail without a block statement let num = obj.k for i in 1 .. num: obj.k *= i echo obj Run \--- This is awesome! I now have more than one solutions to understand more complex macros than the `quote do` ones.
Sponsors page bugged?
[https://nim-lang.org/sponsors.html](https://nim-lang.org/sponsors.html) Status has been a sponsor for 10 months, yet the total amount equals only 1 month of sponsorship.
Re: Language Design Question: Backend C vs LLVM IR
But there's also [https://github.com/arnetheduck/nlvm](https://github.com/arnetheduck/nlvm) \- so you'll likely get to choose the one you prefer.
Re: Best way to represent AST
Araq, when I try to make a function newBinOp (which just abstracts making a binary operation from a Node), I get ".. you must provide compile-time value for discriminator 'op'" This is what the proc looks like: proc newBinOp(left_node: Node, oper: Operation, right_node: Node): Node = return Node(op: oper, left: left_node, right: right_node) Run What am I doing wrong?
Re: Help getting this macro to work in a for loop
try this: import macros proc replaceSymAndIdent(a : NimNode, b : NimNode, c : NimNode, isLit : static[bool] = true) = for i in 0..len(a)-1: if a[i].kind == nnkSym: if ident(strVal(a[i])) == b: a[i] = c elif a[i].kind == nnkClosedSymChoice or a[i].kind == nnkOpenSymChoice: if ident(strVal(a[i][^1])) == b: a[i] = c elif a[i].kind == nnkIdent: if a[i] == b: a[i] = c elif a[i].len != 0: if a[i].kind == nnkDotExpr: when not isLit: if a[i][0].kind == nnkSym: if ident(strVal(a[i][0])) == b: a[i][0] = c elif a[i][0].kind == nnkClosedSymChoice or a[i][0].kind == nnkOpenSymChoice: if ident(strVal(a[i][0][^1])) == b: a[i][0] = c elif a[i][0].kind == nnkIdent: if a[i][0] == b: a[i][0] = c else: replaceSymAndIdent(a[i], b, c, isLit) macro iterateSeq(a : untyped, b : static[seq[string]], code : untyped) : untyped = let a = if a.kind == nnkSym: ident($a) elif a.kind == nnkClosedSymChoice or a.kind == nnkOpenSymChoice: ident($a[^1]) else: a #echo type(a) result = newStmtList() for item in b: var newCode = code.copy() replaceSymAndIdent(newCode, a, newLit(item), isLit = true) result.add(newCode) #echo treeRepr result #echo repr result #echo "" #result = newStmtList() macro assignField*(obj, fieldName, value: typed) : untyped = let fieldSym = newIdentNode($`fieldName`) result = quote do: `obj`.`fieldSym`=`value` type SomeObj* = object a* : int b* : int c* : int var foo = SomeObj() iterateSeq(field, @["a", "c"]): assignField(foo, field, 50) echo foo assignField(foo, "a", 100) assignField(foo, "c", 200) block: assignField(foo, "b", 300) echo foo Run Also, I noticed you were missing a return type on your macro so I don't know how your code compiled at all.
Re: Generic methods are deprecated?
Well yes, the problem is that we don't attach methods to a type so when you write `G[T]` we cannot instantiate every method that "belongs to" `G`. And methods we don't generate cannot participate in the dispatching process. Now that I've written that, maybe we can instantiate generics during dispatcher generation...
Re: Generic methods are deprecated?
> 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
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
Re: Language Design Question: Backend C vs LLVM IR
First, Nim generally is not slower than C. You can write Nim code which is translated straight to C. But of course you may use high level constructs, which may be a bit slower, or you may do too many heap allocations for example, which can make your code a bit slower. And maybe some library modules are not yet as fast as they could be. Advantage of C++ backend can be, that C++ supports exceptions, with no or minimal runtime overhead. Plain C does not, so some people may prefer compiling to C++. Java-Script backend -- well that is the language of the web, so it is good that Nim supports it. And finally, there is also a LLVM backend available already, with some restrictions. When you are really looking for disadvantages of Nim compared to C -- well Nim executables are small, but not so tiny as a C hello-world of only about 10k. Because Nim has a small runtime library and Garbage-Collector support in its executable. But thinking about that, my former statement is not really true, as we can compile Nim using runtime and GC as external libs, so executable is indeed only a few kB. So maybe GC is only remaining disadvantages. But with newruntime we may be able to use Nim without GC, and for most apps GC is no problem at all.
Re: Language Design Question: Backend C vs LLVM IR
Thank you for your answer. Nevertheless, Nim translates to C, C ++ and others. Why? To offer better interoperability with C besides C ++? And what are the differences in performance? Is C ++ generally faster than the target? And by what percentage is a program written in Nim slower on average than direct writing in C or C ++?
Re: Introducing Norm: a Nim ORM
I have some great news: Norm 1.0.11 supports inserting and retrieving NULL values for SQLite databases. This was made possible thanks to the great [ndb](https://github.com/xzfc/ndb.nim) module. The transition from std db_sqlite to ndb/sqlite was really smooth. I can't wait to see ndb replace all db_* modules in stdlib. As soon as ndb supports PostreSQL, we'll be able to port norm/postgres to it as well, which will make NULL support universal.
Re: Language Design Question: Backend C vs LLVM IR
Compiling to C(++) gives us C(++)'s portability and a dirty/better way to interop with C(++): features like `.emit`, `.header`, `.incompleteStruct`, `.codegenDecl` are harder to do with LLVM. That said, C is a pretty bad compiler target language because it doesn't support precise stack tracing for GCs nor efficient exception handling. Thanks to its preprocessor you never know which identifiers might actually be unusable as object fields (`obj->unix` can fail to compile...). LLVM doesn't have these problems.
Re: Best way to represent AST
Like so: type Operation = enum lit, plus, minus, mul, division Node = ref object case op: Operation of lit: value: int else: le, ri: Node Run
Re: Natural is not positive
It depends on authors. I said that French people generally consider 0 as being neither positive nor negative. For instance, a positive temperature is above 0°C. For the french mathematician group Nicolas Bourbaki, which is a well known reference, zero is both positive and negative. But that not means that all mathematicians (being french or not) agree with this. I rather think that it is a non standard definition of positive (and negative). Bourbaki had certainly good reasons to do this, but I think it makes things more complicated. It’s better when the mathematical definitions are consistent with the common sense. And, in fact, I do not know of any other mathematicians who have adopted this point of view. For Wikipedia in english – see [https://en.wikipedia.org/wiki/Positive_real_numbers](https://en.wikipedia.org/wiki/Positive_real_numbers) – a positive number is clearly greater than zero and, this, from a mathematical point of view. But, even in English, your video shows that there is still discussion on this topic.
Re: Where's the code in `tut1.rst`?
The code is right there, Nim uses an RST version that is not as picky as docutils', so github doesn't show it properly. [https://raw.githubusercontent.com/nim-lang/Nim/devel/doc/tut1.rst](https://raw.githubusercontent.com/nim-lang/Nim/devel/doc/tut1.rst)
Where's the code in `tut1.rst`?
Hello, I was trying to send a pull request for Tutorial 1, but I can't seem to spot any code in [https://github.com/nim-lang/Nim/blob/devel/doc/tut1.rst](https://github.com/nim-lang/Nim/blob/devel/doc/tut1.rst). Maybe this isn't the content that shows up at [https://nim-lang.org/docs/tut1.html](https://nim-lang.org/docs/tut1.html)? If it is, are the code snippets pulled in magically from somewhere while building the docs? 樂
Best way to represent AST
So I'm trying to write my typical calculator program I typically write when learning any language, and I'm having troubles with representing the expression as an AST (by making object which represent each node type, such as BinOp, Number, etc), but am having troubles with the recursive nature of it. Here's basically what I have type Node = ref object of RootObj Number = object of Node value: int BinOp = object of Node left: Node op: string right: Node Run The problem is I want the BinOp object to either take a Number node or another BinOp node as it's left and right fields. How can I achieve this? Should I just abandon using objects and try to use perhaps a tuple instead? (For background, I have light experience with C, Rust, but am much more capable with Python)