Case sensitivity is worse in every way IMO. Look at Nim's implementation of UFCS, which means `foo(bar) == bar.foo`. This means only one possible `foo` that takes type of `bar` can be invoked. There's no ambiguity if `foo` is a method, a proc, or a field - if there were, you'd get a compile time error.
Similarly, case insensitivity, of course, means `foo == fOO == fOo == foO`. Reducing these to one identifier means less ambiguity to the programmer and encourages either using sensible names that can't easily be confused, and/or unambiguous mechanisms like the type system designed for this purpose.
Say you have a constant for 'light enabled' Instead of naming it `lEn`, it's better to use `type LightState = enum disabled, enabled` and write `light.set enabled` for so many reasons. Same goes for pretty much everything. It's worth noting as well that the language is very good at resolving overloads by type, so if you have your own object and create a `len` for it, it's not going to get confused with the string `len` or even a `lEn` constant. Even if you have a `lEn` and `len` that are used in the same context with the same types (why though), you can qualify it anyway with `module1.lEn` or `module2.len`.
The language has so many easy tools to make things more explicit and easier to read at the same time. Ultimately, case sensitivity only really ends up encouraging bad naming practice without adding anything back.
I'm a full time Nim developer and have been for over half a decade. It's completely spoiled me for other languages, it is just ridiculously productive. Rather than an ah-ha moment, it was more a gradual transition from "where's the catch?" to "there's no catch!".
The simple answer is this: anything I want to do, I can do in Nim easier than other languages, while also having direct access to C/C++/JS ecosystems as well.
Productivity:
1. I write pseudocode, it compiles fast and runs at C speeds. Programming is fun again!
2. No `::!>><>^<<@{};` cruft everywhere. Write as you want to read, even spanning multiple lines is clean and without separators.
3. Procedural: only data types and code. No need for OOP/Trait abstractions to be forced into everything (it's there if you must).
4. UFCS and overloading by parameter types make everything naturally extendable: `len("string")` can also be written `"string".len` or `len "string"` - you don't have to remember which way round it goes, and 99% of the organisational benefit of OOP emerges from this lexing rule. A compile time error if you use the same name and parameter types, so no ambiguity.
5. Sensible defaults everywhere: type inference, stack allocated and pre-zero'd variables by default, extend with GC/manual management by type (`type HeapInt = ref int`), GC is deterministic with scope based destructors and move semantics as an optimisation rather than a straight jacket, detailed opt-in control down to assembly as you wish.
6. Arguably the best compile time support of any language.
7. AST procedural metaprogramming is a core language feature. It's hard to express how powerful and well integrated this is. You can just chuck code around and recombine it effortlessly. Whether it's simple DRY replacements, automating serialisation from types, custom DSLs at your convenience, or even generating entire frameworks at compile time from data, you effectively have another dimension to programming. I can't go back to flatland, now.
8. Flexible static typing that's as strict (`type specialId = distinct int`) or generic as you want, with concepts matching any statement against a type. You can also calculate or compose types from static values which is really nice.
10. Fantastic FFI that can even use C++ templates, along with loads of converters/wrappers like c2nim, futhark, pas2nim that add even more sugar to FFI interop.
Portability and glue:
- Single portable executable output.
- Compiles to C89/C99, which covers basically every piece of hardware.
- Compiles to C++ so you have C++ ABI compatibility.
> It's less that "Reddit uses NIM" but rather one guy at Reddit uses NIM to do work.
They are the same thing. No one is saying Reddit bases their entire infrastructure on Nim. The point is just that the language is being successfully used in a business context.
This might not be important to you if you're not a user of the language, but for people that are, it is significant for two reasons: 1) it shows it's 'good enough' to do analytics & data processing for a large, data heavy company and 2) creates confidence/proof it can be used in a business context.
As for technical debt, I doubt that's the case. The post mentions internal tools and processing, these kind of things are often not subject to high developer churn.
Besides, Nim has a pretty easy to read syntax that's similar to Python. People who have talked about onboarding developers to the language (such as https://youtu.be/5wljNaPkU7M?t=586) say it has been fairly straightforward to train for if desired.
Yeah definitely. Unlike Python though it's fast and light on memory, so once you have a prototype it's often already performant enough to be developed into a final product. Things like that save a lot of time and money in the long run.
> the real killer feature to me is the javascript target
Agree, this is amazing because you can share code and data structures between front and backend (for example: https://github.com/karaxnim/karax).
Also, it's really nice having high level stuff like metaprogramming and static typing spanning both targets. Things like reading a spec file and generating statically checked APIs for server/client is straightforward, which opens up a lot of possibilities.
Honestly as someone that has used Nim for this extensively, I think that these days with WASM and TypeScript available this isn’t much of a killer feature anymore.
Backend and frontend in the same language is a massive feature for many reasons, not least performance and uniformity. Adding TypeScript is increasing interface friction and complexity, instead of simplifying things.
Of course, right now this may or may not be easier/harder/feasible with just Nim depending on the project, and many more people know TypeScript, but the ideal of one language > many languages is a worthy one.
What do you mean? I am considering it from both sides.
TypeScript already allows this, i.e. you can build the backend and frontend in one language (TypeScript). Same for most languages that compile to WASM.
My point is that with TypeScript this killer feature is already realised and in a way that is far more familiar to the many thousands of developers that already know JavaScript.
> you can build the backend and frontend in one language (TypeScript)
Sure, from the uniformity side, but what about performance?
It's not just latency performance either, it's resource performance and overheads, such as with embedded servers.
> with TypeScript this killer feature is already realised
It really depends on your requirements whether this is true. Personally, a systems language I can use for web stuff is more useful and has a wider scope to me than running JavaScript or WASM in a systems role, even though it is technically possible to do so.
In the general case I think you underestimate how performant JavaScript JITs are these days. For 99.9% of use cases the performance is enough.
Sure, for embedded it might not be workable, but again- since we're discussing killer features I think we need to think bigger. Embedded is far too small a niche to be considered to be Nim's killer feature, especially when this space is already dominated by Rust which supports WASM very well (and therefore hits the performance + uniformity you desire).
> In the general case I think you underestimate how performant JavaScript JITs are these days.
No, I'm well aware of JS and WASM performance, internals, and pitfalls.
> For 99.9% of use cases the performance is enough.
Again, it depends on your perspective and requirements.
Statistically, PHP is enough for most people so why use TypeScript?
At the edges of the resources bell curve however the details do matter.
It's not enough to say that for those concerns you must use different language and potentially a whole different set of semantics, intricacies, libraries and workflows.
> I think we need to think bigger. Embedded is far too small a niche to be considered to be Nim's killer feature
That wasn't my point, and ironically you might be underestimating how much minimising power and resource usage drives much of the modern world.
Memory/storage + CPU ticks == money.
My point is that a language that can act as a universal tool without sacrificing efficiency, productivity, or extensibility (via AST macros), is itself a 'killer feature'. Nim hits that sweet spot of being easy to read and write as well as 'close to the metal'. It lets me target JS, embedded, and natively interface with C and C++ ABI. That gives me a lot of options with one language. There are other languages that have some of these traits, but not all together in a nice package IMO.
> especially when this space is already dominated by Rust
> Statistically, PHP is enough for most people so why use TypeScript?
In the context of our discussion PHP doesn't make sense as it doesn't have native support for running in the browser. TypeScript is specifically a good choice because it has been built with the browser and the backend in mind.
> you might be underestimating how much minimising power and resource usage drives much of the modern world. Memory/storage + CPU ticks == money.
I have learned over the years that what actually drives the modern world is pragmatism. Sure, performance matters, but when you have to reimplement hundreds of libraries from scratch because the ecosystem doesn't exist then you are losing far too much time (and your implementations of those libraries are likely to be suboptimal). You're better off losing some performance and picking the established language, so that you actually ship your project within a couple of months instead of a couple of years.
Nim has been going now for 15 years and has thus far failed to reach critical mass. With each year gaining that critical mass becomes less and less likely. A killer feature for Nim needs to be so beneficial that it overcomes the lacking ecosystem.
> You mean C?
I was referring to the space of languages that work well on embedded and in the browser. C doesn't support the browser side well.
> TypeScript is specifically a good choice because it has been built with the browser and the backend in mind.
Sure, if your only use case is web front/back end uniformity.
My use case covers web front and back end, but also custom embedded, HPC, ML, simulations, and a lot of other stuff that is simply not viable with TS/JS or WASM.
This language lets me share abstractions and reuse code across all this stuff and use C/C++/JS/Python ecosystems directly.
All the above are possible with just JS. Yes, you can even run JS on a microcontroller: https://www.espruino.com/
The V8 JS/WASM engine, however, is written in C++ for good reason.
TS/JS/WASM/web is built on people counting ticks and aligning bytes to give even the floppiest callback spaghetti of frameworks the overhead to be responsive as abstractions increase.
> I have learned over the years that what actually drives the modern world is pragmatism.
I agree, except I think it's more pragmatic to have one language that can service any industry.
TS/JS ain't it, from my perspective.
> reimplement hundreds of libraries from scratch because the ecosystem doesn't exist then you are losing far too much time
Why would you reimplement libraries from scratch instead of using FFI?
FFI is one of the many, apparently unrecognised, 'killer features'.
Specifically killer is FFI with ABI compatibility to C++.
The pragmatic approach is always to stand on the shoulders of giants and FFI with existing libraries for the reasons you listed.
I'm surprised to hear you say that to be honest as you've used the language for years.
Is there an experience behind it?
> You're better off losing some performance and picking the established language, so that you actually ship your project within a couple of months instead of a couple of years.
Well, I don't disagree with the sentiment, but this is more of a commentary on the job market/cost of business than capability.
Again, though, it really depends what you're doing.
Chucking out a web app for an internal tool and distributed websites have different requirements.
> Nim has been going now for 15 years and has thus far failed to reach critical mass. With each year gaining that critical mass becomes less and less likely.
This is a strange perspective to me. Programming languages aren't food left out of the fridge, they're tools to do a job.
Python was made in the 1980s and took decades to even be known about.
Why did people start using Python? Because it was readable, convenient, and very productive.
Why did it become popular? Because people used it more...
What you call 'critical mass' is just a visible hiring pool.
Companies need confidence to find or train people in the language, and developers need confidence they can pay their bills by learning it.
Confidence is increased when people hear of business use, say, if FAANG started a some minor project with it, and it feeds back.
I'd agree embedded is a pretty niche area, and that it's likely not a killer app for Nim. Though it does bring a fair bit of attention.
However Rust doesn't dominate embedded. That's still C or even C++.
Rust has a lot of embedded crates, but supports a pretty small subset of hardware given the number of crates and amount of effort poured into them. The trait system particularly sucks for modeling hardware, IMHO, and with the "re-write the world" mentality it means there's still quite a bit of pain.
So it seems rosier than it actually is -- for now. Rust on embedded is gaining momentum.
> However Rust doesn't dominate embedded. That's still C or even C++.
I don't disagree. What I meant specifically is that Rust dominates the space where you want to target embedded and the browser (Rust does well on embedded and has good WASM support). C/C++ does not support the browser well at all (you can say that it supports WASM too, but Rust has far more front-end frameworks that actually target the browser than C afaik).
Ah, gotcha. Rust's tooling for WASM + embedded is pretty good.
I actually want to get Nim + WASM running on embedded so we could do our own MicroPython like setup and not require people to know how to flash the hardware directly.
I know Andreas doesn't care for WASM, but Nim could support native WASM relatively easily. It already does a "re-looper" for the JS backend AFAICT. which is the biggest challenge of WASM.
100% my experience too. GC in Nim is a rounding error at worst and is often statically elided, anyway. Performance is almost entirely about memory access patterns and you have the same access to this as C.
In other words, performance in Nim is entirely down to the algorithm used, which is a nice place to be.
> you often have quasi-singleton classes called "FooManager", then a single instance called "foo_manager".
Like this:
type FooManager = object
var foo_manager: FooManager
> Now... are these colliding? Or not, because the first letter _is_ case-sensitive?
Well as you correctly reason, the first letter's case distinguishes them.
Convention in the language is for types to start with a capital letter and instances start with a lower case letter.
> What does "fooManager" map to then?
It maps to the `foo_manager` instance because underscores are ignored, they're just for you. By the way, underscores are exceedingly rarely used in Nim code because they're not semantically significant, why bother.
Still, if you like you can use them in your code, and others can choose not to as they want. Clashing identifiers are a compile error so no worries.
Searching has never been a problem for me in years of using Nim but there is `nimgrep` bundled for style insensitive search. Also I'm no RE wiz, but seems like RE might help if it came down it.
Just to stress myself as an anecdote though, I have years in the language and it hasn't come up yet for me, and I've never needed to use `nimgrep`.
I'm really curious, do you have any examples? I can't think of any that wouldn't be better served by using the type system.