What's your experience with Nim?
from popcar2@programming.dev to programming@programming.dev on 31 Aug 10:27
https://programming.dev/post/36627765

I’ve been researching programming languages to find a good, high level language that compiles to a single binary that is preferably pretty small. After tons of research, I landed on Nim and used it to make a quick txt parser for a project I’m doing.

Nim seems absolutely fantastic. Despite being sold as a systems programming language, it feels like Python without any of its drawbacks (it’s fast, statically typed, etc.) - and the text parser I made is only a 50kb binary!

Has anyone here tried Nim? What’s your experience with it? Are there any hidden downsides aside from being kinda unpopular?


Bonus: I want to give a shoutout to how easy it is to open a text file and parse it line-by-line in this language. Look at how simple and elegant this syntax is:

import os

if paramCount() == 0:
  quit("No file given as argument", 1)

let filepath = paramStr(1)

if not fileExists(filepath):
  quit("File not found: " & filepath, 1)

for line in lines(filepath):
  echo line

#programming

threaded - newest

vermaterc@lemmy.ml on 31 Aug 10:54 next collapse

What is your use case? Isn’t memory cheap nowadays?

popcar2@programming.dev on 31 Aug 11:01 collapse

The small binary part is just for fun - but generally my use case is to have an easy to use language that can cross compile easily so I can just pass binaries to the person I’m working with.

vermaterc@lemmy.ml on 31 Aug 15:01 collapse

I believe single binary compilation is not that uncommon these days. You can do that with Go or C#. Apart from obvious ones like c++.

I mean, I don’t want to discourage you, but from my experience choosing not popular language is not a good Idea if you want to actually accomplish something

Peereboominc@piefed.social on 31 Aug 11:36 next collapse

I have no idea about Nim but have you checked Go (Golang)? It does the things that you need: single binary, cross compile, easy to learn (except methods on an object are a bit weird at first).

Next to that it is also stable, not dying soon and lots of dependencies to extend the language.

Anyway, if you like Nim, go for it.

popcar2@programming.dev on 31 Aug 12:28 collapse

Go would probably be my 2nd choice. I haven’t used it much but my initial impression was that it felt kind of boring to write with, and a hello world would end up being a ~2mb binary which put me off a bit. I could give it another shot in the future, but I’m busy enjoying Nim so that probably won’t be any time soon.

Sxan@piefed.zip on 31 Aug 13:23 collapse

Take a look at V. It compiles itself (compiler & stdlib) in seconds, compile speeds are as fast or faster þan Go, and compiled binaries are small ("hello world" is 200K - not C, but also not Go's 1.5MB). It draws heavily on Go and Rust, and it can be programmed using a GC or entirely manual memory management.

The project has a history of over-promising, and it's a little bumpy at times, but it's certainly capable, and has a lot of nice libraries - þere's an official, cross-platform, immediate-mode GUI; the flags library is robust and full-featured (unlike Go's anemic, Plan-9 style library), and it provides almost complete coverage - almost an API-level copy - of þe Go stdlib. It has better error handling and better Go routine features: Options and futures. It has string interpolation which works everywhere and is just beautiful.

Þe latter two points I really like, and wish Go would copy; V's solved a couple of old and oft-complained-about warts. E.g.:

fn divide(a f64, b f64) !f64 {
  if b <= 0 {
    return error("divide by zero")
  }
  return a/b
}

fn main() {
  k := divide(1, 0) or { exit(1) }
  println('k is ${k}')
  // or, you can ignore errors at the risk of a panic with:
  m := divide(1, 2)!
}

Options use ? instead of !, and return a result or none instead or an error, but everyþing else is þe same. Error handling fixed.

Þe better goroutines are courtesy of futures:

res := spawn fn() { print('hey\n') }()
res.wait()
// no sync.Wait{} required
// but also:
rv := spawn fn(k int) int { return k*k }(3)
rv.wait()
println('result: ${rv}')

it does concurrency better þan Go, and þat's saying someþing. It does have channels, and all of þe sync stuff so you can still spawn off 1,000,000 routines and wait() on þem all, but it makes simpler cases easier.

It's worþ looking at.

Edit: URL corrected

popcar2@programming.dev on 31 Aug 15:18 next collapse

Okay, þ is not going to happen, just say th.

Anyway, I did try V before Nim and found it way too unstable (which is corroborated by every other blog post talking about it). I also couldn’t get the language server to work no matter what I did, it just fails to start which isn’t a good first impression. This isn’t even mentioning all the drama behind the scenes for this language.

thingsiplay@beehaw.org on 31 Aug 15:32 collapse

Is the linked .org site correct? I got this one vlang.io

I never programmed in V, but it surely looks interesting. One interesting part is to have multiple paradigms and ways to manage the memory:

There are 4 ways to manage memory in V.

The default is a minimal and a well performing tracing GC.

The second way is autofree, it can be enabled with -autofree. It takes care of most objects (~90-100%): the compiler inserts necessary free calls automatically during compilation. Remaining small percentage of objects is freed via GC. The developer doesn’t need to change anything in their code. “It just works”, like in Python, Go, or Java, except there’s no heavy GC tracing everything or expensive RC for each object. Autofree is still experimental and not production ready yet. That’s planned for V 1.0.

For developers willing to have more low level control, memory can be managed manually with -gc none.

Arena allocation is available via v -prealloc.

Sxan@piefed.zip on 31 Aug 16:42 collapse

I got this one https://vlang.io/

Typed from memory, on my phone. My bad!

Ephera@lemmy.ml on 31 Aug 12:16 next collapse

I don’t have proper experience with it, I just built a small prototype with it back in 2021, to evaluate it for a project. But yeah, apparently these were my notes:

Nim: Significant whitespace [derogatory], no interfaces/traits, imports throw random functions into scope like in Python (plays a big role with supposed object-orientation, as methods don’t get imported along with a type; they’re loosely attached and just imported along), somewhat ugly syntax

Apparently, past-me wasn’t as big on the syntax. 😅

But I can see why, because this is the code I wrote back then, apparently (I wanted to create a OS configuration framework à la Puppet, Ansible etc.):

main.nim:

import strformat
import role, host

let host2 = Role(
  description: "sdadsj",
  code: proc (host: Host) = echo "sakjd"
)

echo host2


type Role2 = ref object of RootObj
  description: string
method deploy(self: Role2) {.base.} = discard


type KWriteConfig5 = ref object of Role2
  cheese: string
method deploy(self: KWriteConfig5) = echo fmt"Deploying: {self.cheese}"


let test = KWriteConfig5(
  description: "Deploy KWriteConfig5.",
  cheese: "cake"
)

test.deploy()


let rolerole = Role2(
  description: "RoleRole",
)

rolerole.deploy()

host.nim:

type Host* = object

role.nim:

import host

type Role* = ref object of RootObj
  description*: string
method deploy(self: Role) {.base.} = discard

Certainly some syntax elements in there where I have not even the faintest guess anymore what they would do…

atzanteol@sh.itjust.works on 31 Aug 12:49 collapse

Apparently, past-me wasn’t as big on the syntax. 😅

You were right. Using whitespace for code blocks is literally the worst option.

FizzyOrange@programming.dev on 31 Aug 14:17 collapse

I dunno I would say Lisp syntax is probably the worst option. Or APL style.

atzanteol@sh.itjust.works on 31 Aug 15:26 next collapse

You make a strong argument! 😆

bitcrafter@programming.dev on 31 Aug 15:58 collapse

Lisp syntax would not even necessarily be that bad if in practice people did not lump all of the closing parentheses in a place where it is really hard to visually match them with their respective opening parentheses so that it is hard to immediately see what is going on. (I have been told that the trick is to read the whitespace instead of the parentheses, but that does not actually help because the whitespace is not significant in Lisp!)

FizzyOrange@programming.dev on 31 Aug 17:17 collapse

Yeah I agree. Presumably they don’t do that though because you’d end up with pages of nothing but ).

I never understood why they don’t add just a little syntactic sugar. You don’t need much to take it from a mess of brackets to something comprehensible.

anton@lemmy.blahaj.zone on 01 Sep 20:46 collapse

I never understood why they don’t add just a little syntactic sugar. You don’t need much to take it from a mess of brackets to something comprehensible.

It was in the original design, but not the first implementation. By the time someone got around to it, people where used to S-expressions.

psycotica0@lemmy.ca on 31 Aug 12:21 next collapse

For comparison: rosettacode.org/wiki/Read_a_file_line_by_line

atzanteol@sh.itjust.works on 31 Aug 12:47 next collapse

it feels like Python without any of its drawbacks

Uses whitespace for code blocks though. I figured we’ve moved past that.

Joker@piefed.social on 31 Aug 14:01 next collapse

I thought we moved past that complaint 20 years ago. It’s not as if you won’t indent your code anyway.

atzanteol@sh.itjust.works on 31 Aug 14:34 collapse

We moved past it because everone realized it was a stupid idea. Rust, go, etc abandoned it and rightly so. It causes more problems than it’s worth.

bitcrafter@programming.dev on 31 Aug 15:51 next collapse

A more fundamental difference between Rust and Python is essentially that the former is expression-based whereas the latter is statement-based, so arguably you need delimiters for code blocks in Rust because an expression can contain a block that itself has statements in it, whereas there is (sadly) no equivalent in Python. (Having said that, even if this weren’t the case, it would probably still have used curly braces for delimiters because it wants to look a bit like C++ to make it more palatable for that group, not because deep wisdom was involved.)

There are lots of things to not like about Python, but the lack of curly brackets that would just be redundant anyway is not one of them. You hardly alone in your opinion, but you are not speaking for “everyone” either.

atzanteol@sh.itjust.works on 31 Aug 16:07 collapse

I deal with the syntax on a daily basis though. Moving code around is objectively more difficult with Python since IDEs can’t always know where the block should be tabbed to. Sometimes it is correct at guessing, sometimes not. And when it’s not all I can think of is “why the fuck am I dealing with this?”. It’s a non-issue in proper languages. Just simply doesn’t exist. The IDE there can know where things should be tabbed to. It’s a problem created explicitly by the language syntax.

bitcrafter@programming.dev on 31 Aug 16:36 collapse

I work with Python on a daily basis as well and this has never been a big deal for me. So in short: speak for yourself.

Joker@piefed.social on 31 Aug 16:36 collapse

Meanwhile, Python is one of the most widely used programming languages.

jaemo@sh.itjust.works on 01 Sep 14:31 collapse

If a zillion people do a silly thing, it’s still a silly thing.

Joker@piefed.social on 01 Sep 18:27 collapse

The point is it's a dumb, old argument that apparently hasn't affected adoption of the language. Python is immensely useful and significant whitespace is a big, fat nothingburger. It's just silly to still be debating it after all these years. The time for that was like 30 years ago.

hornywarthogfart@sh.itjust.works on 02 Sep 03:04 collapse

Yeah, it’s like going to a restaurant and only judging the food by the restaurant’s decor. It is arguing something that doesn’t matter and most people get over it after they’ve worked in a number of languages.

It just doesn’t matter and instead adds noise to the language feedback loop for something that isn’t changing and isn’t a problem to begin with.

FizzyOrange@programming.dev on 31 Aug 14:16 next collapse

Seems like they allow () code blocks too, so it’s kind of the worst of both worlds…

popcar2@programming.dev on 31 Aug 15:20 collapse

I don’t get the hate for whitespace personally. It was maybe an issue 15 years ago, but modern code editors easily solve its issues. You can collapse whitespace blocks, the editor can automatically replace spaces with tabs, etc.

atzanteol@sh.itjust.works on 31 Aug 15:31 collapse

It solved a problem that didn’t exist and created problems that hadn’t previously existed.

There’s a reason every python “intro” begins with “spend 20 minutes setting up an editor to deal with whitespace” properly.

It makes moving code harder. It makes jumping around code blocks harder. Often the ide can help but sometimes it can’t.

In any curly-brace language these are things I simply don’t need to even think about. But in Python it’s a pain.

Yes it’s not the end of the world. Yes I can spend hours fine-tuning my editor. But… Why should I even have to? Why create these hurdles for no gain?

bitcrafter@programming.dev on 31 Aug 15:42 next collapse

I spend a huge amount of time working with Python and regularly do things like refactoring and do not run into all of this pain that supposedly exists, and never have. I think that you should stop speaking on behalf of “everyone”.

atzanteol@sh.itjust.works on 31 Aug 15:45 collapse

I’m not speaking for everyone. Just everyone with taste.

bitcrafter@programming.dev on 31 Aug 16:02 next collapse

More like everyone whose text editor is apparently Notepad…

atzanteol@sh.itjust.works on 31 Aug 16:04 collapse

The best argument I’ve heard for whitespace blocking is “it’s not that bad when you get your text editor configured”. That’s an excuse, not a reason.

bitcrafter@programming.dev on 31 Aug 16:35 next collapse

A text editor that indents a block when you press “tab” is not hard to find and takes all of 30 seconds to set up.

hikaru755@lemmy.world on 01 Sep 13:14 collapse

Idk know what editor you’re using, but it worked perfectly fine out of the box with IntelliJ. Nothing compared to the hassle of setting up a proper Eslint setup for typescript, honestly.

And I’m not trying to defend python here, I don’t touch that language except under duress, and I do prefer C-style code blocks as well. But this is kind of a pointless argument.

jaemo@sh.itjust.works on 01 Sep 14:29 collapse

I mean, you speak for me here, for sure. Python is just silly.

sirdorius@programming.dev on 31 Aug 18:01 next collapse

No clue what you’re talking about honestly. I’ve worked on a 7 million line python codebase, and while python had tons of issues, whitespace was not one of them. You can easily move things around and have never seen a bug due to bad indentation.

BackgrndNoize@lemmy.world on 01 Sep 16:49 collapse

20 mins setting up an editor, lol what fantasy world are you living in, I’ve been using Python for years never had to do much other than install some VScode extensions

FizzyOrange@programming.dev on 31 Aug 14:19 next collapse

I just use Rust for this. You can make the binaries fairly small if you put a bit of effort in. Plus it’s not a niche language, and you get the benefit of a huge community. And your code is pretty much fast by default.

The only real downside is the compilation time, which is a lot better than it used to be but still isn’t great.

communism@lemmy.ml on 31 Aug 16:24 collapse

Yeah tbh I’m not sure what the reason for using a systems programming language other than either Rust or C would be. Rust by default for safety (and it’s as performant as any other systems language), C if you either need to work with an existing C codebase or want to be able to more easily do unsafe stuff. Or if you need to compile quickly. I’m sure the other languages have their benefits but not to the extent where I would both want to learn it and have use cases for it where I would choose that language over Rust or C for a project.

msa2@mastodon.sdf.org on 31 Aug 16:53 next collapse

@communism @FizzyOrange Sometimes you want modern features and safety without the headache that is writing Rust. Rust is a complicated language. I just want something simple without a million footguns.

FizzyOrange@programming.dev on 31 Aug 17:16 next collapse

Rust is fairly well known for not having footguns (except async Rust at least) and for not being a headache.

I guess it can be more complex than something like Python or Typescript though. I would say that extra complexity is not a big deal compared to the pain you’ll have to deal with working with a language as niche as Nim though.

msa2@mastodon.sdf.org on 31 Aug 17:19 collapse

@FizzyOrange Footguns as in C. Headache as in rust.

FizzyOrange@programming.dev on 31 Aug 17:42 collapse

Headache isn’t a word I’d associate with Rust. More with Ruby or Python (at least until uv mostly saved us).

TehPers@beehaw.org on 01 Sep 01:03 collapse

uv is love. uv is life.

I’m still trying to get people at work to use it. It’s one of the few tools out there that takes Python from intolerable spaghetti to readable and maintainable.

bitcrafter@programming.dev on 01 Sep 01:27 collapse

I have found that conda proves to be

. . .

a fairly good

. . .

alternative to pip as well.

TehPers@beehaw.org on 01 Sep 01:45 collapse

conda isn’t much of an alternative to pip. It’s more of an alternative to venv. Unless you’re referring to conda’s dependency management, which I’ve admittedly never used.

And until pip uninstall foo uninstalls unused transitive dependencies too, you’ll have to drag me back.

communism@lemmy.ml on 31 Aug 20:32 collapse

I’m not really sure what people mean by Rust being a headache/weird/hard/etc honestly. It was a learning curve but nothing crazy, and I’ve come to really like the ways Rust works—it makes my life way easier in the long run to be able to solve problems at compile time so I don’t have to debug undefined behaviour at runtime. But to each their own of course—if another language works for you then it works for you.

sus@programming.dev on 31 Aug 17:23 collapse

Nim is more “high level, automatic memory management by default, but you can go 100% manual if you need to”, though the reality of doing that is basically the opposite of rust’s “everything you need to do is well-documented and solid”

TechnoCat@lemmy.ml on 31 Aug 15:12 next collapse

I wrote a small program that hits a few NWS endpoints and prints out formatted to the terminal. I wrote it in fish, typescript, rust, and nim. Most of my experience is in typescript, rust, java, and kotlin. Nim was my favorite of the bunch. Some syntax things were not my cup of tea, but when you have programmed in so many languages it starts to not matter and feels more like lipstick.

My biggest con with nim was that most of the nim libraries I came across are unmaintained and incomplete and undocumented. I think the language and toolset is pretty great though.

speq@lemmy.dbzer0.com on 31 Aug 15:43 next collapse

I like Nim very much. It’s like Python to write in, very expressive and easy to read, but compiled. I think it’s a very good choice for small utilities as well as systems programming.

What I don’t like is some people in the project being dicks to others but I just use the language and try not to care about it.

AstroLightz@lemmy.world on 31 Aug 16:47 next collapse

How is compiling Nim binaries compared to Python? I know on Python, the most common choice is PyInstaller, but that only compiles binaries for the type of system it is executed on.

sus@programming.dev on 31 Aug 17:09 next collapse

Nim is a compiled language by default, and supposedly cross-compilation is usually as simple as

apt install mingw-w64
nim c -d:mingw myproject.nim

though I haven’t really tried doing it (and my general impression of nim is anything “slightly obscure” like cross-compilation still has a non-zero risk of running into unexpected thorny bugs)

popcar2@programming.dev on 31 Aug 17:50 collapse

What the other person said. Cross compiling is as simple as adding a flag assuming you have the dependencies. I tried it and it works well (though my programs are pretty simple). See also the official docs on cross-compiling.

who@feddit.org on 01 Sep 05:00 next collapse

I picked it up because I liked the syntax and systems programming capabilities. At least on the surface, it’s fast and expressive.

My main criticisms of the language: the meta-programming features can quickly draw the programmer into unpleasant complexity, and the official docs don’t make it easy to discover small bits of important info when you don’t already know where to look. (And the latter problem makes the former worse). It’s a work in progress, of course, and I believe these problems could be fixed.

I got productive with Nim in a month or two. I dropped it when I found that the BDFL is both routinely insulting to people, and hasty in closing legitimate bug reports. These are both big red flags in my book. I don’t want to have to interact with him again, and I don’t want any of my work to depend on him.

ZILtoid1991@lemmy.world on 01 Sep 06:51 next collapse

D >>>>> Nim

stinky@redlemmy.com on 01 Sep 14:06 next collapse

what are you indicating here

bitcrafter@programming.dev on 01 Sep 15:04 next collapse

They are making a funny facial expression while wearing Nim on top of a tall hat.

ZILtoid1991@lemmy.world on 01 Sep 15:25 collapse

dlang.org

stinky@redlemmy.com on 01 Sep 18:52 collapse

I meat the redundant greater than signs

Kissaki@programming.dev on 01 Sep 19:31 collapse

Are you attempting to indicate D much better than Nim or from D to Nim?

ZILtoid1991@lemmy.world on 02 Sep 07:33 collapse

Yes

SlartyBartFast@sh.itjust.works on 01 Sep 20:31 next collapse

Scary movie

insomniac_lemon@lemmy.cafe on 01 Sep 20:32 next collapse

I haven’t done enough to consider myself a programmer, but I could’ve written your post. It hits a niche that I have long wanted from programming.

You should check out the Godot 4 bindings if you haven’t already (gdext-nim, see my post on !nim@programming.dev). There’s also one for Raylib (specifically, Naylib).

My biggest functional gripe (that I can say for certain is not just me) was that support for (Bellard’s) TCC was dropped. It was nice for quick prototyping, though Clang is a pretty efficient middleground/default.

popcar2@programming.dev on 01 Sep 21:02 collapse

I have looked into the nim GDExtension and it looks nifty. I haven’t tried it yet though because it might not be totally ready, some github issues make it sound like it could be a pain to work with.

insomniac_lemon@lemmy.cafe on 02 Sep 02:27 collapse

I dunno, do you think it’s too rough for prototypes or jam-like games?

Seems to me like many of the issues are likely specific, workaround-able stuff. It’s mainly developed by 1 person, so pretty much any type of involvement (even posting issues or showing off projects) could help improve the future of the project.

In some cases you can keep your logic in its own file and not dependent on any engine. For instance I made a (non-game) software demo (number converter) for the 3.X bindings and then easily redid the GUI and rewired it for the 4.X bindings. (similarly I made a polygon-from-text-format parser for Naylib, I could transfer it but Godot has polygon editing so less need there)

BillyCrystalMeth@slrpnk.net on 02 Sep 07:25 collapse

Never tried Nim, but I saw this on lobste.rs and thought of you: miguel-martin.com/blog/nim2-review