4 ms·
I like nim, though I agree that the toolset isn't there yet. However I have encountered an interesting quirk with nim that kind of drove me crazy. In a lot of
by big-green-man 2y ago
I like nim, though I agree that the toolset isn't there yet. However I have encountered an interesting quirk with nim that kind of drove me crazy.
In a lot of languages, string types are syntactic sugar for arrays or lists of chars. And usually, when you try to parse a string as a list, because it's just syntactic sugar, it works flawlessly. In nim it is also true that strings are just lists of chars, but for some reason the compiler will not allow you to treat it as such! It seems to have all kinds of special corner cases about how you can do one thing or another that behave differently. It doesn't really seem to have a holistic fundamental design or form, it feels to me like just a bunch of stuff slapped together.
But if you can get to know the quirks, it's incredibly powerful, if for no reason alone, that tooling exists to transpile nim into anything. Well, almost. A core part of the design philosophy is to leverage as much existing tooling as possible, and so it inherits this property and enables you to compile nim for just about any architecture and into any language. This to me is incredibly powerful.
- elcritch 2y agoThe primary reason for the separate string type is to interop better with the various backends. The default C backend appends an extra null termination to ease C compatibility.
- big-green-man 2y agoYeah I think I looked into it and read something like that, I guess when your primary goal is interoperability with already built systems you've got to make trade offs like that and they'll show through in the experience, but it doesn't change the fact that nim feels a little incoherent when you're trying to learn it. It's fine though, I like nim a lot and the value in the language significantly outweighs the downsides to learning those little quirks.
- archargelod 2y ago> In nim it is also true that strings are just lists of chars, but for some reason the compiler will not allow you to treat it as such! That's actually a feature - Nim is designed to be a type safe[0] language. Type safety has a number of advantages: - Compile-time checks: Type system catches many potential issues and silly bugs early at compile time. - API discoverability: IDEs and other tools can provide better autocompletion and type hints because they know exactly what operations are available on a string. Nim tries to strike a balance between flexibility and type safety. Instead of having strict restrictions, you have explicit control with slightly more verbose code. For example, if you want to treat a string as an array, you can use the `openarray` type (`openarray` is a special type that acts as interface to all array-like types and is supported by most of stdlib): var hello = "Hello, World" proc foo(s: seq[char]): bool = discard proc bar(s: openarray[char]): bool = discard echo foo(hello) # this doesn't compile because string != seq[char] echo bar(hello) # this compiles because openarray[char] is compatible with string / seq[char] / etc.. [0] - https://en.wikipedia.org/wiki/Type_safety https://en.wikipedia.org/wiki/Type_safety
- big-green-man 2y agoBut a string is a seq of chars in nim. I ran some type checking code that showed me that that is what it is. So how could it violate type safety by treating it as such?
- archargelod 2y agoType of a string is `string`, the fact that it's internally a `seq[char]` is just an implementation detail. > So how could it violate type safety by treating it as such? By not allowing you to treat a type as a type it's implemented with, Nim could prevent some logical errors. Here's a good example of such logical error from Wikipedia: > For instance, inches and millimeters may both be stored as integers, but should not be substituted for each other or added. Or example with strings: Nim has `Path` type that's implemented as `distinct string`. You can't mix and match Path and string, unless you explicitly convert their types: import std/paths let prefix = Path("/usr") let bins = "bin" echo prefix / bins # not allowed echo prefix / Path(bins) # allowed This makes it a bit harder to do something bad or stupid by accident.