Re: Perfecting Nim
We are talking past each other due to multiple possible interpretations of english language terms (do we need a technical standard for english?). I'm using the term standard in the sense of _technical standard_ as described in [Wikipedia](https://en.wikipedia.org/wiki/Technical_standard). Let's denote a standard library interpreted this way as a _standardised library_. However, the Nim community seems to interpret the term standard as an adjective as in " _a standard hotel room_ ", - synonym with terms such as normal, usual, baseline, customary or prevailing. Let's denote a standard library interpreted this way as a _de-facto library_. I'm using the term Nim 1.0 language (specification) in the sense of ISO/IEC 9899:2011 language (specification), which includes, among other things, the C standard library. However, the Nim community seems to interpret the term Nim 1.0 language in stricter sense as the things specified in [Nim manual (specification)](https://nim-lang.org/docs/manual.html). I'm inclined to agree that at this point of Nim language maturity there is no need to rigorously specify a standarised library. However, the need may raise later when competing implementations start to appear. The [BASIC programming language](https://en.wikipedia.org/wiki/List_of_BASIC_dialects) is a cautionary example of how a language may disintegrate into non-compatible dialects with their own sets of documentation if no adherence to a specification is required (and with things like [MicroPython](http://docs.micropython.org/en/latest/pyboard/library/index.html), Python seems dangerous too...). With these readings in mind, it makes sense to state that the de-facto library that ships as part of the Nim reference implementation is not part of the Nim language specification and therefore out-of-scope problem in perfecting Nim. Some concerns still remain: * The Nim reference implementation should be made available as source and as installation (the language part implementation of the compiler without any out-of-spec-libraries bundled in) * Will there be any assurance that the de-facto library will remain backwards-compatible after 1.0 (append-only, deprecation marks instead of replacements)? * Some elementary arithmetic and string handling functions like _sqrt_ and _intToStr_ should be moved from library to language specification to make the language more general-purpose. * It is unfortunate that the Nim language and the Nim compiler are both called Nim (in contrast to C/gcc, Java/javac, Python/CPython, Go/gc, ...). To avoid confusion, the latter should be renamed to something else ( _nimcc_? _nimdom_?), after which I 'm grittingly willing to accept the liberal use of the term standard as in " _nimcc standard library, the de-facto library for Nim language users_ "). * It must be clearly stated somewhere which library modules are available for which environments and targets - maybe in some kind of table form. I hope this helps.
Re: Perfecting Nim
@aedt don't really think that is a good idea at all re halting Nim 1 for destructors. Nim can be/is a good general purpose language. If you look at any top 10 programming languages list only C and C++ have manual memory management. Most top 5 lists now days will also include Python, Javascript, Java and C#. The majority of programmers use GC languages. So why limit all the majority to satisfy a minority of programmers by holding back version 1? Most GC based languages have challenges and trade offs when it comes to threads and for most purposes Nim's thread model while it may not be ideal is good enough. This Perfecting Nim thread is the wrong mental frame. No programming language is perfect. They all have trade offs. Like every other language Nim will not be perfect. So its time to get over that idea, release Nim 1.0 this year, and the destructors can continue to be worked on for version 2. If perfection or nearing perfection was a requirement for a successful language then languages like PHP and Javascript would not have enjoyed the success they have.
Re: Perfecting Nim
+1, mratsim. What I want is convenience and still catering for people who wanted more performance for low level stuff. Convenient and practical.
Re: Perfecting Nim
@aedt I think it's a question of resources. Given the current promising state it would be better to release now, garnering interest and goodwill and probably new hands to help on ironing bugs and use cases that the current tiny community doesn't need in my opinion. Also that allows those with interest to pitch in before the door is closed. The current GC/manual memory management is already good enough to start doing productive stuff with Nim (alloc0, allocShared, ptr object).
Re: Perfecting Nim
Controversial opinion but I'll just leave it out there because I'm a fan of Nim: Halt Nim 1.0 until Nim 2.0 destructors suggested in [https://github.com/nim-lang/Nim/wiki/Destructors](https://github.com/nim-lang/Nim/wiki/Destructors) is standardized. Eventually for systems programming people will want to do manual memory management. It also gives you an extra market so people don't just discard Nim just because it has a thread unsafe GC. The market for manual resource management and RAII will never end and C++ will always be there for this. Why not penetrate this area where people advocate Rust so much? Systems/Games people want fully deterministic performance more than safety afaik. Also, with package repo... ([https://github.com/nim-lang/packages/blob/master/packages.json](https://github.com/nim-lang/packages/blob/master/packages.json)) does NOT look scalable to me. Just saying. Thanks for reading.
Re: Perfecting Nim
These modules are part of the "standard library", but the standard library is not the language, whether the C spec lists `` or not is irrelevant.
Re: Perfecting Nim
Conventionally standard library is part of the language spec. If you look at the C Reference Manual, you'll see that roughly half of the spec is devoted to specifying the stdlib. It would remove a lot of confusion if the set of .magic modules would be named as the standard library and the "standard library" something else. Also I think that language conformance test suite should not test any modules that are not part of the language spec. Also, Rosetta Code examples should be solved (as much as possible) with the tools provided by language spec, not with help of non-standard modules like strutils or sequtils.
Re: Perfecting Nim
Libraries that contain a `.magic` are "by definition" part of the language, not part of the "standard library" which is not part of the language spec. That means `system`, `threadpool`, `typeinfo`, `macros`, `typetraits` are special.
Re: Perfecting Nim
Ill try to show that Nim 1.0 programming language standard library should not be 1:1 with the bunch of modules that currently ships with the Nim reference implementation. **Preliminaries** A programming language is not only a syntax, but also a runtime. At minimum, a runtime should offer functions for input and output. The more batteries in the runtime, the better for the end user. When designing a runtime, especially these non-functional requirements should be considered: performance, implementability, maintainability, applicability, usability and portability. The portability of runtime library can be ensured by standardizing it, whereupon it is called the language’s standard library. A standardized library ensures that source code will work across implementations and later versions. For example, standard library 1.0 source code written for compiler A implemented by company B for operating system C targeting machine D will work without refactoring with standard library 1.6 for compiler X implemented by community Y for virtual machine Z. **Definitions** * stdlib: The forthcoming Nim 1.0 programming language standard library * cnimc:The Nim compiler reference implementation targeting C * jsnimc: The Nim compiler reference implementation targeting Javascript * nimcc: The application containing cnimc and jsnimc that can be installed from [here](https://nim-lang.org/install.html) * nimcc library: The collection of modules that ships with nimcc, as listed [here](https://nim-lang.org/docs/lib.html) **Theorem** stdlib should be a non-empty proper subset of nimcc library **Proof, in 3 parts** Part 1: stdlib should be non-empty (Proof by contradiction) If stdlib is empty, it would essentially mean that stdlib would equal system.nim. To prove that stdlib should be non-empty, it is enough to show one module that should be included in stdlib. We use macros module for this. It is stated at Nim official website, Wikipedia, and Nim in Action book that metaprogramming (hygienic term rewriting macros) is one of Nim’s core features. A standard library without macros module would therefore define a language that is not Nim. Part 2: stdlib should be proper subset of nimcc library (Proof by reductio ad absurdum) To prove this, it is enough to show one module that is in nimcc library but should not be in stdlib. We use winlean module for this. If nimlean is part of stdlib, it means that jsnimc must implement every function in it to be compliant. However, it is practically impossible to implement windows inside browser sandbox where javascript runtime tends to run. Part 3: stdlib should not be a superset of nimcc library (Proof by contraction) The label 1.0 signals that the language is production-ready. If stdlib would contain a module that is not shipped with nimcc, it would mean that no reference implementation for Nim exists, and therefore the language specification could not claim 1.0 status. By elementary logic, the conjunction of parts 1-3 proves the theorem. QED. **Corollary** If Nim standards committee indeed decides that stdlib will not be 1:1 to nimcc library, the set of modules shipped with nimcc must be renamed to something else.
Re: Perfecting Nim
I never thought anything was inconsistent about `newSeq` and `newString`. Strings and sequences are value types, but they are still GC'd. * * * Oh, and the other thing to note is that we're working on the new runtime, where strings and sequences can be non-GC. This brings both types closer in nature to primitives, as mentioned. Personally, I always initialize my strings and sequences with `""` and `@[]`. I think this feels better than using a proc, because these types are builtins. So if we are considering switching to `initSeq` and `initString`, how about just `""` and `@[]`?
Re: Perfecting Nim
Making `nim program.nim` functional goes against the purpose of this thread. Unneeded stuff should be removed, not added.
Re: Perfecting Nim
I like the idea of making nim program.nim functional. I don't know if it should run or not (maybe 50% of the times?).
Re: Perfecting Nim
@sherjilozair That are very subjective recommendations, with some disadvantages. "nim program" as a default alias for "nim c -r program.nim" with hidden executable would mean that program is compiled again and again for each execution -- until user discovers that he can just execute the binary. Maybe indeed less surprising for people who only know scripting languages. For nimcache -- I am using this to not stressing my SSD too much (with /tmp mounted to ram): cat nim.cfg nimcache:"/tmp/$projectdir" You are talking about "beginner programmers" \-- when you mean people with absolutely no prior programming experience, then we have to think about if we should recommend Nim at all for these people. I think Nim can be a good first (and only) language for these people, maybe at high school or first university course. But we know that it is not yet used there. And for self studies Nim may be still a bit hard, as we have not large numbers of very good quality documentation and large user communities in all mayor native languages. Also we don't have libraries for all possible use cases beginners may be interested in, and finally the compiler still has some minor bugs, which also is not that optimal for beginners.
Re: Perfecting Nim
This is not so much about removing features, but about making nim friendly for beginner programmers, or programmers who work at a higher abstraction layer (Python users). In my opinion, the fact that nim actually compiles to C code, and then compiles to binaries, and then runs the binaries should be "hidden" from the user. For this, I propose three changes * nim program.nim should behave like nim c -r program.nim, instead of giving an error. This would give the user a feeling of "it just works", instead of having to read the man page. * nimcache should not be visible. It should be renamed .nimcache and should start hidden. * The binaries should be created inside .nimcache if the user used nim program.nim or nim -r program.nim. The binaries should be visible at current working directory only when the user explicitly asks for them using nim c program.nim. The proposed changes are meant to make the experience of the beginner programmer easier and less surprising. This isn't to make the experience of the advanced programmer any harder. The current behavior could just be a few flags away.
Re: Perfecting Nim
> @[] and "" don't have to actually differ from nil, it could be an > implementation detail. Pretty much like option[ref T not nil] can be > implemented as ref T. Yep. And that's how it will be done.
Re: Perfecting Nim
@didlybom But strings and sequences ARE already treated a little differently than plain reference object types, aren't they? The most trivial example being: strings have their literals and sequences (and arrays) have `openArray` but neither string nor sequence has object constructor. So what now? Well, just treat them more or less like primitives. If neither string nor sequence have `nil` as a proper value then they will certainly not behave like reference types. What is interesting: @[] and "" don't have to actually differ from `nil`, it could be an implementation detail. Pretty much like `option[ref T not nil]` can be implemented as `ref T`.
Re: Perfecting Nim
> @didlybom The names follow > [https://nim-lang.org/docs/apis.html](https://nim-lang.org/docs/apis.html) (a > document that is not well known). initT is used for value-based types, newT > for pointer-based types. newSeq and newString depart from it because they > were created early on. Thanks for the explanation @araq. The problem is that seqs and strings are likely to be the very first kind of thing that a new user is going to create. The fact that those two deviate from the general rule makes the rule hard to understand, IMHO. What good is a rule that is not applicable to the most common use case? Wouldn't it make sense to define "initSeq" and "initString" procedures? It those were then used in the tutorials and the documentation it would help new users learn the rule you mentioned. Ideally the existing newSeq and newString could be marked as deprecated as well, but I do not know if that would be feasible given that it would basically make almost _[all](https://forum.nim-lang.org/postActivity.xml#all) existing nim code deprecated.
Re: Perfecting Nim
performant code when you want -> sane/safe/easy defaults
Re: Perfecting Nim
@Allin I didn't find basic2d and basic3d, in the docs the links are dead.
Re: Perfecting Nim
I like the idea to make `seq` and `string` default `@[]` and `""`, we can use `{.noinit.}` to make them `nil` if care about performance.
Re: Perfecting Nim
@Allin: I really like your plan. We need to change it in its details though. Will write an RFC and post the link to it here.
Re: Perfecting Nim
To keep the ball rolling with std lib pruning, here's my proposal (kind of a sketch, not to be taken too literally). * * * **Level 1 - "Nim Kernel"**: System modules that every Nim compiler supports (embedded systems, virtual machines, etc). algorithm base64 complex critbits deques hashes endians fenv intsets json lists (+sharedlist) locks logging macros marshal math nativesockets parseutils pegs random rationals ropes segfaults sequtils sets stats streams strformat strscans strtabs strutils subexes tables (+sharedtables) threadpool times unittest * * * **Level 2 - "Nim Standard"**: Nim Standard library modules for currently popular mobile and desktop operating systems. asyncdispatch asyncfile asynchttpserver asyncnet dynlib encodings httpclient md5 memfiles mimetypes net os osproc parsecfg parsecsv parseopt2 posix rdstdin selectors ssl terminal unicode uri winlean * * * **Level 3 - "Nim Extra"**: Modules available as installable Nimble packages. All available out-of-the-box in a Nim Legacy Distro. asyncftpclient asyncjs basic2d basic3d browsers cgi cookies coro db_sqlite db_mysql db_postgres distros dom events fsmonitor future highlite htmlparser httpserver iup jsffi lexbase matchers mersenne mysql nre odbcsql oids options parseopt parsesql parsexml pcre postgres re rst rstast rstgen scgi sexp sha1 smtp sqlite3 strmisc xmldom xmldomparser xmlparser xmltree
Re: Perfecting Nim
Araq, `{.experimental.}`, that's an exceptionally (haha) pragmatic and likable plan! Even the exceptions are fine with an exception-free core because that makes a no-exceptions flag quite feasible in the future, when a better option emerges. What about the crufty / obsolete / inconsistent stuff in the std lib, of which there is plenty, by most accounts in this thread? Incidentally, pruning the std lib and putting it in nimbles instead also makes for a better upgrade path in a beautiful, experimental-free world, because it's easy to code up alternatives for the brave new world. On practical ways forward, I also like the suggestion for levels-of-packaging that would let people eat the batteries-included cookie and have it.
Re: Perfecting Nim
@didlybom The names follow [https://nim-lang.org/docs/apis.html](https://nim-lang.org/docs/apis.html) (a document that is not well known). `initT` is used for value-based types, `newT` for pointer-based types. `newSeq` and `newString` depart from it because they were created early on.
Re: Perfecting Nim
One small thing that feels inconsistent in the standard library (and which has confused me a bit since I started using nim) is that in addition to the new keyword different standard library classes have different new and/or init procedures. For example there is newSeq and newSeqWith, newTable, newTableWith, initTable, etc. Perhaps there is a clear rule to choose which is which and when to use which (or create initXXX vs newXXX procedures on your own libraries), but (on the surface) it feels inconsistent and is confusing (at least it was for me). I'd prefer that you could always use new (and define a constructor procedure if you need some custom initialization). I also agree that it would be best for not nil to be the default, but I don't know if that is too much of a change this close to v1.0. It would probably break a lot of existing code (and perhaps find a few bugs in the process).
Re: Perfecting Nim
@Araq sounds like a good plan to me. If that plan was implemented would it be feasible to launch V1 by end of June? I think v1 plan should be a plan that allows v1 launch this year. If Nim used Swift release strategy it would probably be version 11 by now.
Re: Perfecting Nim
Hi all, still a nim-noob but I enjoy writing code in Nim. Nim is great and I use it both for non-os and os environments. Please don't purge the range-types; they are super useful and every serious language should have it. In my eyes the dead-code elimination feature within Nim is unneccesary; the backend could handle that if needed. Especially within barebone environments auto "dead"-code elimination is a problem. Exceptions are also useful; but I also agree with Arag here that a context- value could be used instead. Within low resource environmens (ATtiny for instance) Exceptions are bloated. For me it's important that everything could be excluded(switched off) if not needed. Actually a porting guide is missing for beginners to get in fast into the internals. For me it's acually unclear which code is platform dependent and which parts are not. Some modules could be externalized indeed especially these which rely on others (protection against cyclic dependencies) Also the c2nim tool could be a little bit more powerful - in my eyes it's a little bit frustrating for beginners using it (error messages and tweaking almost every header line of code; very much manual work)
Re: Perfecting Nim
Range types and arrays with non integer indices are very useful. Range type is not distinct int it is int and it makes the difference. I plan develop range types functionality further, it is very important to have type system that will reject all invalid instances whether it is int, float or object. Range restrictions are only small subset of needs to be applied. I have an idea how to generalize range types idea into types with arbitrary restrictions, not just range restrictions.
Re: Perfecting Nim
I haven't been on the forum for quite a while, just the chat and I would also like to put my wishlist of things to remove here. * the range type. Well just use `type range[low,high: static[int]] = distinct int` No need for this to be a language feature * arrays with a size that is not an integer. Generics in Nim are (almost?) powerful enough to implement an array type that emulates this behavior. * int64 and int and distinct types, where float64 and float are just alias types. This is unnecessary. * concepts in their current form. I like the idea of concepts, but i don't like the current implementation/syntax. The current syntax confuses type expressions with value expressions. Changing the syntax in a non-ambiguous one will break a lot if now all code that uses concepts in the current state. It should be declared highly experimental to use concepts in the current state. * The strutils package.
Re: Perfecting Nim
Patching the stdlib to use concepts where it makes sense instead of `openArray` is also a fine idea. It's really used a lot -- (`algorithms`, `strutils`, `sequtils`, `random`, `stats`, etc.). `Iterable` & `Indexable` concepts make sense to me as a decomposition for all those interface use-cases. Something so basic as a dependency should not be in something called `sugar`, though. Some new stdlib module (`concepts`, `stdtypes`, `typeclassess`?) would be a better place for standard concepts that many other modules depended upon. But this is off-topic for "what to remove".
Re: Perfecting Nim
`openarray` as a concept was raised here: [https://github.com/nim-lang/Nim/issues/6528](https://github.com/nim-lang/Nim/issues/6528) but in light of the discussion for memRanges/slices/pointer+len/span that happened here: > * > [https://github.com/nim-lang/Nim/issues/7337#issuecomment-373641158](https://github.com/nim-lang/Nim/issues/7337#issuecomment-373641158) > * > [https://github.com/nim-lang/Nim/issues/5753](https://github.com/nim-lang/Nim/issues/5753) > * > [https://github.com/nim-lang/Nim/pull/5957](https://github.com/nim-lang/Nim/pull/5957) > * > [https://github.com/nim-lang/Nim/issues/5437](https://github.com/nim-lang/Nim/issues/5437) > I'd rather have openarray be renamed span (slice and range are taken) and be able to cover (borrow) anything from arrays/seq to slices to pointer+len **without copy**. Furthermore an `Iterable` concept can be introduced (which would work with openarray and user-defined types). `items` and `pairs` can work on this `Iterable` concept. Similarly, an `Indexable` can be added for `[]` and co. Those concepts can be added to sugar.nim.
Re: Perfecting Nim
> Default Not Nil (and cleaning up the associated initialization that springs > from this). Newbies always get caught with a seq that hasn't been > initialised. If you want nil, be explicit about it. The better solution for today's Nim is to remove `nil` from seqs. Internally `@[]` can be `nil`, but there is no reason to expose this implementation detail. `len` already returns 0 for nil seqs. The same is true for `string`.
Re: Perfecting Nim
Well it's time we talk about what v1 should be about. In my opinion v1 should be today's Nim with features that don't work well put behind the `{.experimental.}` switch or removed altogether. Oh and of course we should remove the already deprecated stuff. But the goal should be to keep much of the existing Nimble packages working, so removing features like `method` or exceptions would do more harm than good. We have a track record of good backwards compatibility (though it's far from excellent) and I do not want to give that up lightly just because "ha, ha, we were not v1". Nim suffers from an overly long development process and I can see room for improvements for nearly every aspect in it. But this hunt for perfection should start after v1. In fact, I have a hard time finding programming languages in wide use today that is not long past v1: Lua is at version 5, Python at 3, Swift at 4 (!?), C# at 6, Java at 8, D at 2 etc etc. Nobody is able to release the perfect v1, not even Rust. We need a compromise between stability and room for language experiments. Let's consider `not nil` as an example: There is no doubt It does not work well. What should we do? **V1**: Put it behind `{.experimental: "notnil".}` **V2**: Make it work well. -- OR -- ignore the annotation altogether and enforce explicit initializations instead. Then `nil` can only creep into your program when you write it. Could turn out to be the best compromise as I push for "pointer free" solutions otherwise anyway. `method`: It does not work well. **V1** : Put it behind `{.experimental: "method".}`. **V2** : Map it to some superior `interface` solution, turn it from multi methods into single methods. Every usage I've seen in the wild did not rely on the "multi" aspect of it anyway. Exceptions: A harder problem. Solution: Ensure critical stdlib operations are behind a `.raises: []`. Move more of the offending stdlib into Nimble packages. `.closure iterator` are weird beasts. **V1** : Put it behind `{.experimental: "closureiterator".}` **V2** : Put it behind `{.experimental: "resumableproc".}` `.discardable`: Let's just deprecate it. `TaintedString`: They are useful and a tiny amount of complexity. Let's keep them. Other candidates for `.experimental`: `concept`, `void`, `self`. But let me clear that `experimental` means more "we're not yet happy with how this feature works" rather than "we will remove it again".
Re: Perfecting Nim
> has the idea of openArray being a concept been considered? It seems to make > sense - an array has a set of properties that concept describes well: > indexable, len, etc Certainly, but I want to keep `openArray` and turn into borrowed array slices. The borrowing aspect is hard to achieve with a concept. The better way to do it is to simply patch the stdlib to use a concept where it makes sense. Also today's `openArray` does not turn the proc into a generating proc/generic which has its advantages.
Re: Perfecting Nim
@jlp765 I agree about default non-nullability - for sure. @Araq, has the idea of `openArray` being a `concept` been considered? It seems to make sense - an array has a set of properties that `concept` describes well: indexable, `len`, etc.
Re: Perfecting Nim
Default `Not Nil` (and cleaning up the associated initialization that springs from this). Newbies always get caught with a seq that hasn't been initialised. If you want `nil`, be explicit about it.
Re: Perfecting Nim
While excess can be bad, and there are inconsistencies that should be repaired, I think a "batteries included" stdlib is a good thing. E.g., the recent `enumerate` for loop macro in `tests/macros/tforloop_macro1.nim` should probably be in `lib/pure/sugar.nim`. I think the duplication (`re` and `nre`, `parseopt` and `parseopt2`) should go. `mersenne` does seem pointless. Maybe game programmers use `basic[23]d`? I think `coro` is a good example of low level programming in Nim, but I don't know if needs to be in the stdlib. I like `set[]`, "do", converters, and exceptions. Exception-free alternatives in the stdlib sounds good, though. I think `using` is a good idea. I don't usually use dynamic dispatch of any kind, but the Lisp world swears by multi-methods for such and they are more general than the usual first-slot-only OO dispatch. No opinion on holey enums vs distinct ints or `discardable`. I never liked non-case-sensitivity or `TaintedString`. I think it would be nice if `openArray` could be more "open". It could become a first class `concept` needing only `[]`, `len`, etc. when concepts are ready enough. That may be already planned.
Re: Perfecting Nim
`bitsets` \- I haven't used them but I know I will someday and I wouldn't remove them. If they can be moved to a nimble package, that's fine with me. `exceptions` \- I'm 100% behind Araq that "bubble up" is the right default. Yet, I tend to favor having a Result type (similar to Rust) and having a set of macros to rewrite code to achieve this (both block-level and proc/method-level, along the lines of Rust's `try!` macro but better) . I think it would be simplify Nim's core and also simplify the job of many macros. It's always tricky to deal with exception paths in macros such as async, iterators, etc. Disclaimer: I have not used any C++ code with Nim and don't plan to do so. Perhaps exception-throwing C++ code can be wrapped at the FFI layer such that it catches exceptions returns Result types. I wouldn't change anything for v1, and I'd go towards `Result` \+ macros for v2. `methods` \- I'd definitely remove them if we get concepts with vtrefs. Those who are suggesting the different nimble packages for interfaces (e.g. `interfaced`) have not tried them, I'm afraid. They work only for the really simple use-cases. At the very least, we would need to make them work with generics, which I expect will require some non-trivial work. Until that's done, and some project uses them extensively, it is not a reasonable alternative, IMO. I wouldn't change anything for v1 and I'd wish for concepts with vtrefs for v2 (if we're not getting them for v1). `converters` \-- They've been useful to me so far, so I wouldn't remove them. I haven't run into issues with them either. `do` \-- Very useful. I don't find the syntax/notation offensive.
Re: Perfecting Nim
I'm glad @arnetheduck started this thread. I appreciate his minimalist leanings and the nod to Antoine de Saint-Exupéry. * `exceptions` Can't live with'em, can't live without'em. I agree that they're questionable, but like @Araq said there's no obviously better alternative. I know that in D their implementation is tightly tied with the GC. Do they present problems for the GC free Nim we expect to see in the year 2525? In the SPARK subset of Ada exception handling is banned, though exceptions can be raised. Also, Rust is a different beast than Nim, maybe if Nim had algebraic data types we could use Option and Result types and do like Rust. I'd suggest leaving them alone for v1. * `method` I understand @mratsim's position I think; he'd like some kind of dynamic dispatch that is relatively inexpensive but not necessarily method. I think that's achievable before v1. * `bitsets` No one suggested removing bitsets, just moving them to a library. This is analogous to the discussion in D about moving associative arrays from the language to a library. This makes sense; if you can't write it so that it's efficient and convenient as a library, you can either modify the language so that it's possible (the solution I like) or make it a built-in. I believe as much as possible should be in libraries. I don't think it matters much whether this is fixed now or later, so maybe it is better to wait until after v1. @arnetheduck, do you have a reason that they need to go **now**? * ` converters` Opinions vary here, I generally agree with the dictum that explicit is better than implicit, especially in a language with overloading. I'd like them gone. * `do` I have no strong feelings one way or the other on this one. * `Enums with holes` Good catch @GULPF, I agree, out with v1 * `{.discardable.}` Another good catch, out with v1
Re: Perfecting Nim
from my point of view things that should go out: * `do` every time I read code which uses do I have to think hard what's going on. * `using` never used it and looks a bit strange to me * `method` is not really usable in it current shape. But we need some OOP. things that should stay or improve: * `converters` at least we need a mechanism to do implicit controlled conversion. I am happy with something better. * `exceptions` we are not in a nim only world. If you interface with C++/JS code you will need them. * `bitsets` they are handy one thing that should improve is object variants. In their current form they are very low-level and error prone and not very elegant. I would prefer something like GADTs or the Enums in Haxe. **But this is completely out of topic for v1.**
Re: Perfecting Nim
To be able to eat and keep the cake, consider a three-layered architecture: kernel, modules, distros. **Nim kernel** Would contain just the core features so that Nim can compile itself and majority of Rosetta code problems can be solved. Very compact, very stable, very efficient, very well tested and documented. (But not designed to be very useful (or even expressive) without additional modules) **Nim modules** When kernel stuff is not enough, coder can install packages (modules and their documentation) from various repositories. Basically all language constructs that don 't need magical compiler support should be implemented as additional modules (as macros, I guess). **Nim distros** Would contain the kernel and a pre-selected collection of modules, tools, extra documentation, and such enabling a flying-start to Nim development. There should be three "official" distros available: * Nim Legacy: Anything you need so that your old Nim 0.18 code still compiles * Nim Standard: The standard Nim programming language environment (lean and mean) * Nim Dev: For those who develop the Nim itself Then hopefully communities would emerge that curate distros for their needs: Nim for Android, Nim Gaming, Data Science Nim, Nim Web, Nim Enterprise Edition, ... (And in a perfect world one could install multiple distros simultaneously without hassle) * * * This three-layered architecture could achieve the following: * Core devs (like writers of alternative compilers) can concentrate on perfecting the kernel * The decision of which features to include in 1.0 would not have such criticality (when in doubt, leave it out) * Availability of application-specific distros would keep anyone happy (all your favourite features are still pre-installed there!) " _We can solve any problem by introducing an extra level of indirection._ "
Re: Perfecting Nim
I think there are probably a lot more lower hanging fruit than 'do' notation and coroutines. 'do' notation is super handy. Coroutines is fairly fundamental for Actor model and generators.
Re: Perfecting Nim
Completing my first answer with tings that came up after: * `converters` currently are a bit unsafe. They can happily trigger ambiguous calls when a converter to numeric type exist. I don't mind them going especially if the int literals stuff is sorted out. Or it would be nice if we could restrict implicit conversion like it can be done to template: [https://github.com/nim-lang/Nim/issues/7520](https://github.com/nim-lang/Nim/issues/7520) * `discardable`, I feel this should be explicit by default, too easy to discard error codes. Can be moved to sugar.nim * `TaintedString`: it's a good idea, reminds me a bit of the Haskell IO Monad in practice though, a bit cumbersome to use. At the very least parseutils should provide useful proc to deal with those otherwise I guess everyone is just doing $tainted. Also it's another concept that will surprise (delight/block?) newcomers. * `methods`: I rely on them for the neural net part of Arraymancer, I don't mind them going as long as the performance is similar of faster as I call them several times per second and Nim's methods have very low overhead especially when inlined (only 3x the proc cost). * `do`: Yeah it's a super strange notation, I do need a way to have multiline arguments though.
Re: Perfecting Nim
Replying because thread is broken and 3rd page is linked but 404s
Re: Perfecting Nim
This is a thread that I wanted to create myself in preparation for v1. Thank you for creating it. For everyone reading this thread: **please let us know your opinions of what needs to go before v1 is released.** I'll probably read everyone's answers later, but here is the quick small list off the top of my head: * `do` notation, it always felt unnatural in Nim to me and I dislike it to this day. * `coro` module, it doesn't seem to be used much.
Re: Perfecting Nim
I'm not a fan of exceptions but the alternatives that are usually suggested are worse reinventions of exceptions. Error handling is really not that hard to analyse: In case of an error you can only do a couple of different things: * Let it "bubble up" the call stack. * Retry the operation. * Report/discard and continue with the next instruction whatever that means. * Trap/quit/die. Arguably that is just a shortcut for bubbling up the call stack and let the OS's "exception handler" deal with it. * Turn it into a regular value, no Option[T] or Either[T, E] do **not** count. <\-- I'm personally in favour of this, but nobody agrees with me and in theory it can make errors harder to diagnose. What exceptions do is they claim "let it bubble up is what you want in over 90% of all the cases out there so we make this the implicit, fast, default model of operation". To refute exceptions you need to come up with a decent statistic that proves this wrong or you need to argue that "implicit is bad". "Implicit is bad" ignores too much the point of using computers in the first place in my opinion which leaves us with (b) statistics. So bring them on, I say.
Re: Perfecting Nim
How do you feel about exceptions? I always disliked exceptions in C++ and found comfort in C, which lacks them. Yet, when I found Nim I realized that exceptions aren't so tricky. Perhaps this is because of 2 really important features: * The GC: In C++ you must take extra care to write exception safe code. RAII and exceptions must go hand-in-hand, and it's a tiring mental overhead. In Nim, Stuff Just Gets Deallocated (tm). I always associated exceptions with GC languages, so they fit better into Nim than C++. Of course, we are now developing a new run-time that will do away with many GC complexities. This shouldn't affect the exception system though, am I correct? The refcounting will just be deterministic instead of deferred and cycle-resolving?? * The `defer` keyword: Really this makes resource management doable. Until destructors are 100% ready it's really The Way to handle non-`ref` types, since these types can't be "finalized". So I'm not against exceptions in principle for Nim specifically. However it would be a good idea to note that many targets of a "systems language" don't favor exceptions, because they both change control flow and can be expensive (since Nim targets C++ we can use zero cost exceptions and performance isn't an issue). The only issue then is philosophical: how does one handle errors? Is it at the call site w/ a return value (no exceptions - my favorite in general), through unwinding exceptions (current state of things), through multiple return values (like Go), through unrecoverable panics (terrible) or through some state like `errno` (really terrible). IMO, the only alternative is something like `Result` in Rust or Go-like tuple return values. We would **need** a chaining solution like the `?` in Rust. I don 't want this: try: obj.getInner().upgradeToRwChannel().attachListener(callback) except Something: echo getCurrentExceptionMsg() handle() ... to turn into this: let inner = obj.getInner() if inner.isErr: handle() let upgrade = inner.upgradeToRwChannel() if upgrade.isErr: handle() let res = upgrade.attachListener(callback) if res.isErr: echo res.msg handle()
Re: Perfecting Nim
Well there is an RFC to make some of the "interfaces" nimble packages part of the stdlib. Again, let me clear: When I say "remove X from Nim", I mean "replace X by something better/slightly different (that in the best case can be done with macros)".
Re: Perfecting Nim
On the topic of `method`: I like the flexibility that it provides. I am not a die-hard OOP programmer - e.g. I prefer a Rust or C style where one uses either custom structures or uses composition. However, without `method` OOP support in Nim would be quite fundamentally limited
Re: Perfecting Nim
That's a very good idea but it's not universally applicable, a feature needs to justify its implementation complexity and the training/documentation aspects (a bigger language is harder to teach etc). Also, when I say something like "I want to remove X from Nim" I generally mean to provide a better mechanism that also happens to do / allow for X. For example, `converter` could be turned into a more general "overloading resolution hook" that is consulted when type checking a call expression failed. Note that this is just an example, I doubt an "overloading resolution hook" is what Nim needs...
Re: Perfecting Nim
One more idea. Can it be more federated decision? For example: if we have a volunteering maintainer to support a feature and to resolve its reported issues then it will remain. So people instead of theoretical discussion will vote with their time (real asset) instead? I think you will likely to come up with realistic/pragmatic design in this case and over time build a team of maintainers.
Re: Perfecting Nim
> I like Nim's enums and I often have to import C++ enums so I can't choose if > they are with holes or not, yet need to wrap them. Distinct ints are not > anywhere near in terms of usability: I need to know how many distinct values > out there, have string <-> value parse/format. This can be done with a macro.
Re: Perfecting Nim
Not sure if this was ever discussed so I will throw this idea here: The Nim compiler has very complicated built in type rules for int types handling, to make int, int16, uint types mixable without explicit type conversions. Is is possible move out this logic from compiler into a set of converters defined in stdlib module? Users preferring strictness would not import it and they will need to convert types explicitly, while those who are relaxed can import it. Disclaimer: It is untested idea
Re: Perfecting Nim
Focusing on the stdlib: hopefully already intended, but removing deprecated modules and procs, as well as `md5` and `asyncftpclient`. `md5` is just an attractive nuisance of a cryptographic hashing algorithm, good enough to look appealing but horridly insecure, and to the extent the stdlib has one (there are good arguments for it), it should probably be SHA2. `asyncftpclient` implements a decreasingly relevant protocol. The `asyncio`, `ftpclient`, `sockets`, and `rawsockets` modules have been deprecated since version 0.11. There are a couple dozen procs through other modules: `proc `-`(a, b: Time): int64 {..}`, `proc fromSeconds(since1970: float): Time {..}`, `proc fromSeconds(since1970: int64): Time {..}`, `proc toSeconds(time: Time): float {..}`, `proc getLocalTime(time: Time): DateTime {..}`, `proc getGMTime(time: Time): DateTime {..}`, `proc getTimezone(): int {..}`, the various `isSpace`/`isAlpha`/`isLower`/`isUpper`/`capitalize` procs, et cetera. Agree on several other non-deprecated stdlib modules as well, e.g., `strtabs` and having two different regex modules.
Re: Perfecting Nim
Please, leave exceptions there, there are other methods to handle errors, but they are often cumbersome in an imperative language. Bitsets are also really nice, and they play well with the c pattern of using integers for options and combining them with masks, just in a more readabe way. That said, these are things I do not use: * methods * converters * discardable * TaintedString A large standard library is super convenient: I am happy not to have to reach nimble for a lot of common task, such as writing a webserver or parsing json. Incidentally, it also allows nimble library to have very few dependencies in general, which is good. That said, there **are** things that I think may be safely removed: * matchers * basic2d * basic3d * mersenne (why doesn't it integrate with random?) * parseopt (but not parseopt2)
Re: Perfecting Nim
Please, leave exceptions there, there are other methods to handle errors, but they are often cumbersome in an imperative language. Bitsets are also really nice, and they play well with the c pattern of using integers for options and combining them with masks, just in a more readabe way. That said, these are things I do not use: * methods * converters * discardable * TaintedString A large standard library is super convenient: I am happy not to have to reach nimble for a lot of common task, such as writing a webserver or parsing json. Incidentally, it also allows nimble library to have very few dependencies in general, which is good. That said, there **are** things that I think may be safely removed: * matchers * basic2d * basic3d * mersenne (why doesn't it integrate with random?) * parseopt (but not parseopt2)
Re: Perfecting Nim
* `.discardable`, doesn't play nice with Nim's type inference and is rarely useful. * `converter` * `method`, replace it by an interface macro. * enums with holes, replace it by a `distinct` integer type. * `.borrow` as a builtin, should have been a macro. Exceptions are hard to replace and have their benefits, it's worth its own topic.
Re: Perfecting Nim
**Compiler features I 'd remove** Converters - rarely used feature that complicates the compiler `{.discardable.}` \- I hate this pragma with a passion Enums with holes - barely supported in the compiler, might as well remove them since distinct types can be used instead TaintedString - has basically zero maintenance cost, but it's just another feature that nobody ever uses from x import nil - this is a terrible idea and is mostly used by people new to Nim, who don't fully understand why it's terrible **Compiler features I 'd not remove** Tags - very rarely used, but the feature has potential and I don't think it complicates the compiler much Exceptions - I don't like them, but they are good to have for integration with C++/JS projects **Standard library** I agree that the standard library is to big, it's a graveyard of unmaintained modules. Some modules that could be removed: complex, rationals, nre, strtabs, strmisc, marschal, events.
Re: Perfecting Nim
I think interfaces or something akin to them would be much more useful for the language than methods. I don't know how hard this is to implement - that's not why I'm suggesting it - I just don't find methods particularly useful. I don't generally like exceptions - but I've also been told not use things like nil and to prefer things like exceptions. I think this needs to be sorted out and we either need to go back to doing things in a C like / some other manner or fully embrace exceptions. Or we could invent somethning here - but the current situation isn't ideal. Converters - meh I don't find them particularly useful but I also don't find them harmful. I think they could go just to reduce a feature that probably most people don't use. I think there's been some progress made on shrinking the stdlib and getting rid of some modules or moving some to external libs. That work should continue. Some modules I'd personally get rid of - color, 2d/3dmath all of the db related libraries There are others I'd consider too but I think that's a start... Bitsets - @krux02 - what's the alternative? Could you provide an example or something? I'm also guessing they're pretty relied on throughout the Nim stdlib... What's the urge to get rid of them? What real harm does including them cause? I understand that they could be replaced with more useful features, but something equivalent or close to has to be there. Auto formatting code - yeah some tool that the vscode extension and other editors could use would be great, I agree. I agree with Arr's points about the system lib and general refactoring / renaming suggestions. * Zachary Carter
Re: Perfecting Nim
> What else would you kill off? * method Nim already has the ability to do OO style polymorphism without **method** , I think for those relatively rare cases that this is useful something other than **method** should be provided, maybe something like Ada 2005 interface types. I thought that 's what the **vtref** stuff from the older concepts section of the docs was going to address, but it 's gone down the memory hole. What happened? * Partial case insensitivity Just enforce a particular naming style, be it camelCase or snake_case. * converters Is there a killer argument for these that I'm missing? I find explicit conversion more readable.
Re: Perfecting Nim
> bitsets a really nice macro? also, backend compiler optimizers are pretty good at getting perf for these kinds of ops anyway, and with fewer features in the nim compiler, there's more room in there for good compiler features - better error messages, better transformations.. > exceptions, used in the standard modules only thing worse than exceptions is `both-exceptions-and-something-else` > exceptions, rust + unwrap rust unwrap only gets used in old examples - there's `?` for production code. Nim, thanks to its great syntactic flexibility, could do even better with a macro and a block - being explicit about ignoring errors is a good thing, just like Nim does with `discard` already. > std lib, lots of alternatives * if there's an obviously better one, it'll win * if the std lib is focused, consistent and good, other libs will follow that style and fewer alternatives will emerge * if you really want to provide a canonical or blessed alternative, host it under the `nim-lang` org on github, but leave the coexisting upgrade path open > std lib, nimble means dead if they're useful, they get maintained and if they're not, nimble repo remains a place to keep them forever, unchanged and compatible with whatever other code that manages to use them successfully - combined with semantic versioning, you get the best of all worlds - stability for old stuff, promotion/accessibility for good and useful code and choice for developers > std lib, refactoring The desired refactoring doesn't happen _because_ it 's in the std lib. If it's not in the std lib, it's cheap and easy to refactor letting the old version stay forever frozen in time. > std lib, huge all of `wrappers`, most of `pure`.. why is `json`, `htmlparser`, `smtp` in there??? madness.. there's even an FTP client and two, yes **TWO** ` http` servers!.. then there's `core` and `std` that are just plain weird - what goes where? `posix`, that's a pipe dream if there ever was one - out it goes to be replaced by [https://github.com/nim-lang/Nim/pull/5698](https://github.com/nim-lang/Nim/pull/5698) as an external nimble lib, easy. bring it on, all the radical stuff you'd love to change! only time will tell if the regret article will have yours and it'll be fun to look back
Re: Perfecting Nim
* Dead code elim: make it the default * bitsets: No, I agree with the other posters they are super useful. I can squeeze lots of speed from them without thinking on how to reimplement bitvector, shifts, masking and all that jazz. * Exceptions. I think it really depends on the use case. I really don't like how C and Go must always check the error code or how Rust is plagued with `unwrap` everywhere. I like function chaining and exceptions allow that. I read much more code than I write and any solutions that uses error code will break the program and my reading flow and clutter the intent of the code. Now in lots of cases you can't throw or are forced to use try/except in lots of places. * Huge standard library: what is under github/nim-lang is not all part of the stdlib (for example nim/opencl or nim/sdl2) so not sure what you are talking about. * Auto-formatted code: oh yes a clangfmt would be awesome.
Re: Perfecting Nim
> bitsets I use them almost in every place, and I suppose the compiler does the same. > exceptions I would not remove them, but it piss me off when they are used in the stardard modules. I'd rather check if the result is equals to -1 or is none than have to handle an exception when trying to stablish a new connection. > a huge standard library I do agree there seems to be really old modules that no one use anymore. But there are good reasons for having one: 1. Stuff that is so used that eventually a lot of alternatives would appear (the reason why options were finally added), making it confusing to work with projects that employ each one a different implementation. 2. You should consider whatever is published in nimble as dead aswell, so I would not rely important functionalities in there. In fact, everything that stopped being useful or used in the standard lib ended up being moved to nimble already. Now, system definitely does need a refactoring. You can find there strings, seqs, garbage collection, file handling, stream handling, exception handling ... I'm sure that everything related to files and GC could be separated from the main module. Not that you are going to stop the GC or open a new file in every module of your project. Also nim could use better names for modules. 'os', 'ospaths', 'osprocs' are confusing. Maybe rename osprocs to 'process', and 'ospaths' to 'paths'.
Re: Perfecting Nim
> bitsets - why are these even in the language and not a library? Because they're **SUPER USEFUL** in game development, and from what I can tell lots of people use Nim for game development. You need resistances in you RPG? type Element* = enum eFire, eWater, eEarth, eAir var myCharacterResistances: set[Element] myCharacterResistances.incl eFire if enemyAttack.element notin myCharacterResistances: echo "PREPARE YOUR ANUS" You need to make a tile-based game? type OverworldTileProperty* = enum otpWater, otpLava if otpWater in tiles[playerPosition + playerMovement]: echo "Dude, only Jesus can walk on water" elif otpLava in tiles[playerPosition + playerMovement]: echo "FEEL THE BURN!" Some even use them for game options, intrinsics, key items, etc. etc. As a game developer, this is actually one of the things that made me love Nim. Instead of using macro voodoo to get bitarrays (like in C) or needing an external dependency (like in most other languages), Nim's system.set is everywhere, it's simple and extremely fast. Also, Nim takes a lot of inspiration from Pascal and if I remember correctly bitsets are a native type there too. Regarding the other points, they're all very reasonable. I personally almost never use exceptions, so if Araq wants to go the Rust/Go route is fine by me.
Perfecting Nim
"Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away" With the specter of 1.0 approaching, it seems everyone is keen on squeezing their favorite feature in, but it seems to me that one would perhaps be better served by removing any and all failed experiments and bad ideas first - so here's a thread celebrating the cancers that should, with the benefit of hindsight, not have seen the light of day and that still can be removed nice and cheap (you can be sure it's cheaper now than it will be later, tutorials, stackoverflow and books notwithstanding)! Even half-baked ones are cheaper to remove and readd than to keep and remove later - that gut feeling is right and you'll end up not readding them anyway - when writing the following post 5 years from now, do you really want it to be full of things you knew about but didn't act upon? [http://www.informit.com/articles/article.aspx?p=2425867](http://www.informit.com/articles/article.aspx?p=2425867) I've started the party with [https://github.com/nim-lang/Nim/pull/7669](https://github.com/nim-lang/Nim/pull/7669) \- the dead code elimination _option_ is indisputably useless. Here are a few more, just to get the discussion going * bitsets - why are these even in the language and not a library? * exceptions - this dinosaur leftover from the dark ages introduces all kinds of hidden costs and after decades of trials and experience, gets the downvote * reasoning cost - you totally lose the ability to reason about what the code will do, because critical information is hidden and execution may break off at any time * api/abi cost - when the errors change, the api doesn't so if a library you're using changes, the compiler can't help you * performance cost - error handling (always) has a cost but this is not reflected in the code you write * the most loved language doesn't have them ([https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted)](https://insights.stackoverflow.com/survey/2018/#most-loved-dreaded-and-wanted\)), so it's safe to say they're useless for love * languages that have them (C++!) are scrambling to get rid of them (specifiers deprecated, better options being introduced, like [https://github.com/viboes/std-make/blob/master/doc/proposal/expected/p0323r3.pdf](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/p0323r3.pdf)) * the stalwart of reliability, Erlang, shuns them * here's a nice post on error handling that Araq pointed me to at some point: [http://joeduffyblog.com/2016/02/07/the-error-model/#retrospective-and-conclusions](http://joeduffyblog.com/2016/02/07/the-error-model/#retrospective-and-conclusions) \- no love for exceptions there either.. * a huge standard library - the library is arguably one of nim:s weakest points with lots of inconsistency and poorly maintained parts - cutting it down to a bare minimum would: * free up time to maintain the core parts better * incentivise spending time on making nimble work (well) through dogfooding * provide an upgrade path from bad ideas * provide a playground and staging area for things that _could_ or _should_ actually be in the core library - moving them in there only when they passed the tests of time and quality * manually formatted code - it's 2018 and programs can format code and optimize it for human reading better than humans - no one cares what the format is really, as long as it's consistent What else would you kill off?