Hi,
Some points, nothing special, only my view. I've numbered them, only because it is easier to reply them this way.
Thanks for reading, Peter
1. Nim is an excellent language, the community is helpful. Nim has great potentional. It's just at the perfect spot. It feels like a fast implementation of python which runs everywhere, even on a microcontroller, or within a browser. It is low level enough to make me happy, and the metaprogramming features are just awesome.
2. The most missing feature for me: let newList = map(@[1,2,3], x => $(x+10)). It requires a complex logic from the compiler: the first parameter is seq[int], therefore it calls the function with an int, which returns a string, so newList will have a type seq[string]. I really miss this. I started to debug the compiler to add this feature without luck so far, I can see that this is not trivial. But I miss this.
3. Horizontal spacing (when whitespace matters between operands): it's cool as an option, but I wouldn't like to see it as default. What happens with linebreaks? I've seen two languages with non-standard evaluation: Closure's (+ 1 2) or Q/kdb's "evaluate from the right". I couldn't get used to them. I can see that with other operators ($, &, etc.) it migth be easier to read.
4. I really miss nimfmt, is it possible to reformat my source code each time I save it in Vim? Go comes with this, and tt was very easy to get used to it. Yes, I could call nimfmt by hand. By the way, I think that nimfmt shouldn't remove all my empty lines used to separate code blocks, just should reduce them to one empty line.
5. Can I run a macro for my code without modifying it? Currently I use a block to run my macro (indenting everything), or add a pragma to a function. Would it be possible to turn a macro on with a pragma (so I could turn it on at the begining of the file)? Or import a library with a macro applied on it (i.e. run the macro at all the sources of the library)? An example for the usecase: we could easily check the code coverage of a library in the unit test without modifying the library itself. An other example: it would be easy to write a macro for debug purposes, which builds and prints a tree containing all the function calls (possibly with the parameters as well) at runtime with timestamps (e.g. fib(20) called fib(19) and fib(18)).
6. Nim is great! However, I didn't feel that after reading the tutorial, I almost left. Reading the tutorial I didn't understand what const was about. I didn't know that I can push certain calculations to compile time, for example in const x = fib(20) will be really a constant and the 20th Fibonacci number is calculated at compile time. The when statement came out of blue, I wanted to learn about the language, and when example is about writing cross compiling code. Maybe it would be better if compile time stuffs (const, when, staticRead, compileTime, etc.) were in a seperate section a little bit later. The fact that seq is working at compile time is mind-blowing! We have a hash table when compiling!
7. Reading the tutorial I didn't understand why we need set. I can't use it for strings, it can be very memory insufficient if we have a few items in a large space. I'm missing the point. Could it be mentioned here HashSet as an alternative? By the way, could we combine it with HashSet by using a concept? So all the code which accepts set now could be rewritten to accept a concept, which is implemented by both set and HashSet.
8. In the tutorial I was confused reading about arrays (with the special indexing, can go from 1?), sequences, open arrays, varargs, slices. Tried to memorize their syntax to survive. It turned out that I use seq all the time. I understand that the rest of them are important, but I felt that I was reading small details when I wanted to do something quick following the tutorial. Maybe a short introduction to tables could be sooner.
9. All the things collected from other languages (block by indent, pass parameter to proc by name, e.g. f(x=10), tuple unpacking) are amazing, and integrates well with the language. I could get used to $ and &, they are short, often used, I really started to like them. So many things are awesome! However, the tuple unpacking could work without let or var. Is there a reason not to support this?
10. Macros/templates are amazing! I'm using treeRepr all the time to understand what happens. Would it be possible to convert back from AST to source code, so we could see the inner states? For example with an extra compiler parameter we could have the original source file mycode.nim, after first macro expansion nimcache/mycode.nim1, after second macro expansion nimcache/mycode.nim2, etc., and the final version without any macro/template. Sometimes my source code fails to compile, and it would be great to see what is failing exactly, even play with that intermediate state.
11. Is there a reason why echo can't print the inner types of the compiler? I always had to try echo, debug, or sometimes mix them.
12. Are there any planned features for channels? Like listening on multiple channels at the same time? (I started some work but stopped because I was busy and didn't test on Windows.)
13. There are two type of iterators: inline and closure. Could these be hidden from the user which is used? Also if you create an iterator f(), then you can't assign it to a variable (you can create a function which returns a closure iterator). Can't we reduce one layer here?
14. The var statement in the function parameters is a great idea! It is a new concept I haven't seen anywhere before. Even an int can be changed, and we can be sure that without the var statement nothing can be changed. Well, if the parameter is an object and it has a pointer, then we can change the value where this pointer points (but not the pointer itself). And if we pass a pointer to a function: proc f(x: ref myType) can't change the pointer, but can change the data where it points. Is it possible to promise in a function's definition that I won't change the data where the pointer points? Motivation: please imagine a summer night, the family is already sleeping, and you're doing your regular coding before sleep. It relaxes you. It's the Nim's compiler this time. The code is already full of echo and debug, light music in the background. The functions have very few var in their definitions, looks like an easy job to understand what's going on here, but wait... nearly everything is a pointer.
15. I believe that we should add more rules (please think of the English word concept here) to the functional functions (map, filter, etc.), also to the containers. Rules which you remember, and you can write code without checking the docs all the time. I've started some work, which I'll continue as soon as I have some time.
16. What is rootObj about? It's sometimes there, sometimes not. Complately magic to me.
17. I know that it is a big to ask, but how about ... a weekly email? I get a weekly email about the updates in python (http://www.pythonweekly.com/). Could we have somehing similar for Nim? Containing a list of the new projects, largest changes/fixes, future development plans, best macro of the week, upcoming presentations, etc.
18. Once in a while the question is asked: when will be the release of Nim 1.0? I'm always fear to read the answer. Everybody is eager to have 1.0, but me. Will it come with backward compatibility like in Rust? There are so many things which could be cleaner before finalizing the language.
For 11., try debug(structure).
For 7., yeah it should be called bitset.
For 8., tutorial's here: https://github.com/nim-lang/Nim/blob/devel/doc/tut1.txt
For 9., why? You want to specify var-ness of the variables anyway.
For 15., was working on it, got stuck somehow. Might give it another look today.
For 17., You could start a weekly thread here and ask for new stuff, then compile it into a mail.
For 2., I though there are list comprehensions, which should be able to do such a thing.
#2: While more extensive type inference would be nice, the only thing you really need for this is the type of the argument, e.g.:
import future
let newList = map(@[1,2,3], (x: int) => $(x+10))
While it would be nice to be able to omit the : int, it's not really a life-or-death thing for me.
#7: It's both Nim's Pascal heritage and Nim being a system programming language. I agree that a more specific name might have been nicer.
#9: You can write your own tuple destructuring macro. For example:
import macros
macro `..=`*(lhs, rhs: untyped): auto =
# Check that the lhs is a tuple of identifiers.
expectKind(lhs, nnkPar)
for i in 0..len(lhs)-1:
expectKind(lhs[i], nnkIdent)
# Result is a statement list starting with an
# assignment to a tmp variable of rhs.
let t = genSym()
result = newStmtList(quote do:
let `t` = `rhs`)
# assign each component to the corresponding
# variable.
for i in 0..len(lhs)-1:
let v = lhs[i]
# skip assignments to _.
if $v.toStrLit != "_":
result.add(quote do:
`v` = `t`[`i`])
var x, y: int
(x, y) ..= (1, 2)
echo x, y
(x, _) ..= (3, 4)
echo x, y
#10: Somewhat more limited, but you can also print an AST in source code form via toStrLit. E.g.:
import macros
macro foo(x: untyped): auto =
echo "Tree representation:"
echo x.treeRepr
echo "String representation:"
echo x.toStrLit
quote do: discard
foo(s[0] == ' ')
3. Horizontal spacing (when whitespace matters between operands): it's cool as an option, but I wouldn't like to see it as default. What happens with linebreaks?
Well it's not like the spec is unclear about linebreaks...
7. I'm missing the point.
Not sure how you can miss the point when C code is full of unsigned flags = FOO|BAR|BAZ;.
9. Is there a reason not to support this?
Somebody needs to implement it.
11. Is there a reason why echo can't print the inner types of the compiler? I always had to try echo, debug, or sometimes mix them.
Well sometimes I look at the JSON representation, sometimes at some other representation.
12. Are there any planned features for channels? Like listening on multiple channels at the same time? (I started some work but stopped because I was busy and didn't test on Windows.)
Argh, you can just say so in the PR. Testing it on Windows is easy for us.
13. There are two type of iterators: inline and closure. Could these be hidden from the user which is used?
Yes and I think we should do this.
14. Is it possible to promise in a function's definition that I won't change the data where the pointer points?
No, but I have plans for deep immutability. Worth a new thread though.
16. What is rootObj about? It's sometimes there, sometimes not. Complately magic to me.
Well if you want inheritance, you inherit from RootObj. Not sure what's magic here.
17. I know that it is a big to ask, but how about ... a weekly email?
Meh, we have git commit messages for this. :P
18. Once in a while the question is asked: when will be the release of Nim 1.0? I'm always fear to read the answer. Everybody is eager to have 1.0, but me. Will it come with backward compatibility like in Rust? There are so many things which could be cleaner before finalizing the language.
Dunno. Worse is better. C, Unix and Golang taught me it's much more important to release version 1 quickly rather than producing something that is finished.
Thank you all for the answers, they were very helpful. I especially like the macro for the tuple unpacking :). Let me comment some of the answers, where I have additional information:
For the 17. [weekly email]: I understand that this is a time-consuming task, so I try to help in the content not to take away time from the developers. Please see the thread Weekly email on this forum.
4.[nimfmt]: Inspirated from gofmt, we could have transform this:
var
shorter = 10 #comment one
lognerName = 9999 #comment two
to this:
var
shorter = 10 #comment one
lognerName = 9999 #comment two
This is only one example. I used to think that these transformations are not important, and now I miss it from every language.
For 7.[set]: My post was misleading, sorry about that. I used set a couple of times, I understand why it is useful. I'm asking whether we could have a common interface for set and HashSet, and also wondering whether it could be introduced a little bit later in the tutorial (please feel free to ignore this since I don't have a good proposal).
Thanks again for taking the time to read and answer. Peter
I see a couple of problems with the proposed formatting:
var
shorter = 10 #comment one
lognerName = 9999 #comment two
Firstly, this kind of columnar alignment mistakenly emphasises the affinity of, say, 10 and 9999 when they, in fact, are quite independent. The identifier and its value are what belong together, semantically. Thus, using whitespace to separate them more than necessary is ill-conceived.
Secondly, this is bad from the perspective of version control. If an item is changed, added, or removed then that might require realignment of the other, semantically unrelated statements, causing unnecessary change bloat in the commit.