it feels like Python without any of its drawbacks
Uses whitespace for code blocks though. I figured we've moved past that.
Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!
Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.
Hope you enjoy the instance!
Rules
Follow the wormhole through a path of communities !webdev@programming.dev
it feels like Python without any of its drawbacks
Uses whitespace for code blocks though. I figured we've moved past that.
I thought we moved past that complaint 20 years ago. It’s not as if you won’t indent your code anyway.
Seems like they allow ()
code blocks too, so it's kind of the worst of both worlds...
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...
Apparently, past-me wasn't as big on the syntax. 😅
You were right. Using whitespace for code blocks is literally the worst option.
I dunno I would say Lisp syntax is probably the worst option. Or APL style.
You make a strong argument! 😆
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.
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.
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.
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
What is your use case? Isn't memory cheap nowadays?
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.