"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, 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

I've started the party with 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
  • 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?

2018-04-22 06:59:34

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 your 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.

2018-04-22 09:00:59

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'.

2018-04-22 09:57:59
  • 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.
2018-04-22 10:59:00

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 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

2018-04-22 13:30:41
bpr

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.

2018-04-22 21:24:21

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 Arrrrrr's points about the system lib and general refactoring / renaming suggestions.

  • Zachary Carter
2018-04-23 01:08:01

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.

2018-04-23 06:19:57
  • .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.

2018-04-23 07:21:58

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.

2018-04-23 08:08:09
<<<••1234567••>>>