Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nim is unsafe #4

Closed
dom96 opened this issue Nov 11, 2015 · 23 comments
Closed

Nim is unsafe #4

dom96 opened this issue Nov 11, 2015 · 23 comments

Comments

@dom96
Copy link
Contributor

dom96 commented Nov 11, 2015

...or at least that's what I am told by Reddit/HN.

It seems that this is Nim's reputation now, every single time a discussion about Nim gets off the ground somebody comes along and says something like "Nim would be awesome but it has the same unsafe and undefined behaviour as C". Recent example here. Somebody even asked a question on Quora about this: https://www.quora.com/Is-Nim-really-that-unsafe.

The root of this criticism is here.

I think it's about time we do something about this. Either simply decide that Nim doesn't try to be safe, does try to be safe but provides features which allow it to be unsafe, does try to be safe but a bug causes it to be unsafe, or a combination of those statements. So which is it?

Is it for example fine that

echo("Counting to ten: ")
for i in countup(1, 10):
  var k: ref int = nil
  var l = k[]
  echo($l)

Will not crash in release mode?

Possibly related: #2809

@refi64
Copy link

refi64 commented Nov 11, 2015

It's also Reddit, where they criticize Java but downvote anyone else who dislikes it. Just tell 'em to suck an egg or something...

@Varriount
Copy link

Unfortunately, I do agree somewhat. Undefinable behavior aside (which can be fixed through the codegen) many of the basic types in the standard library easily allow unsafe and inefficient behavior.

A large amount of the pain C/C++ programmers seem to face is from the constant mental modeling that needs to be done to write code that doesn't encounter some odd memory error or cause undefined behavior. Furthermore, the cycle of having to compile, run, and then test your code just to possibly find common mistakes is horribly tedious.

This is what makes Rust so attractive, and Nim... not so attractive. Rust has all that familiarity of C++, coupled with the underlying idea that "anything unsafe should be explicitly approved of by the programmer". However one may feel about the extreme view Rust has taken on this, it nevertheless seems like something that relieves the biggest pain-point of C/C++ programming.

Nim, on the other hand, feels at times a hode-podge of ideas that cater to few. Yes, it has a good GC, procedures, closures, and a compile-time evaluation system. Unfortunately, many of the 'killer features' are underdeveloped or were never subject to enough user feedback to make them really useful.
Take strings, which right now are nillable and copy-on-assignment, making them neither safe nor efficient in the eyes of C/C++ programmers. Even if you are of the opinion that types should be nillable by default, having a nil string is rarely any good, as a much more useful representation is simply an empty string.
Term-rewriting macros are another feature that is sadly underdeveloped. The syntax for describing what a term-rewriting macro is supposed to rewrite gets very complicated, very quickly, and it's often hard to understand how to write an expression to match a certain AST configuration. Some more outside input may have helped choose a more suitable syntax.

I could go on, but this comment is ranty enough as it is. Make no mistake, I want to see Nim grow and become successful, but I fear that the current path it's heading on will make it turn into something akin to compiled PHP.. At some point backwards incompatible changes will need to be made, if only to correct design and efficiency flaws.

@Araq
Copy link
Member

Araq commented Nov 11, 2015

These kind of arguments would be way more convincing if the example actually would not crash in release mode, but it does... Maybe the hacker news people need to actually hack something and look at the results rather than pretending they know everything.

@Araq
Copy link
Member

Araq commented Nov 11, 2015

Take strings, which right now are nillable and copy-on-assignment, making them neither safe nor efficient in the eyes of C/C++ programmers.

Sorry, but you're not speaking for the C/C++ programming community but from your own experiences and you dislike how Nim's strings work. Which is fine, but please don't pretend there is some consensus on this complex topic when there clearly is none. And again, COW can be introduced without breaking semantics make them as efficient as C++'s strings. And back in the days, I analysed a complex piece of software heavily doing string ops (it was a preprocessor not unlike C's) and decided that even COW is too expensive after a certain amount of optimizations has been applied. Java-like code full of accessors is punished by Nim's strings, but that doesn't mean Nim's strings are misdesigned. Add to this the fact that Nim's strings are really consistent with how the rest of the language works and you have the explanation of why Nim's strings are the way they are. That Python and Java do it differently never was a valid concern for me, if I want Python and Java I know where to find them.

@Araq
Copy link
Member

Araq commented Nov 11, 2015

Either simply decide that Nim doesn't try to be safe, does try to be safe but provides features which allow it to be unsafe, does try to be safe but a bug causes it to be unsafe, or a combination of those statements. So which is it?

ptr, addr and cast are the keywords (and pointer/cstring/ unchecked arrays) which introduce unsafety, the rest is safe. The manual is actually pretty clear about it. The missing nil checking is a bug but rather a minor one because it just doesn't come up in practice. If you come up with real world examples where it does come up, it will get a higher priority. Opinions on reddit are not a replacement for actual real world examples.

@dom96
Copy link
Contributor Author

dom96 commented Nov 12, 2015

These kind of arguments would be way more convincing if the example actually would not crash in release mode, but it does... Maybe the hacker news people need to actually hack something and look at the results rather than pretending they know everything.

I think the whole point is that it doesn't crash.

@dom96
Copy link
Contributor Author

dom96 commented Nov 12, 2015

ptr, addr and cast are the keywords (and pointer/cstring/ unchecked arrays) which introduce unsafety

Would it be possible to get an Unsafe effect and mark those using this effect, then we could get something close to Rust's unsafe keyword right?

@Araq
Copy link
Member

Araq commented Nov 12, 2015

I think the whole point is that it doesn't crash.

Yes, and yet it DOES CRASH both with and without -d:release.

@Varriount
Copy link

What about on clang, without the address sanitizer option?

@Araq
Copy link
Member

Araq commented Nov 13, 2015

Would it be possible to get an Unsafe effect and mark those using this effect, then we could get something close to Rust's unsafe keyword right?

The point of an effect is to prevent something at compile time. Can unsafe code call safe code? Yes. Can safe code call unsafe code? You better enable this too. So what's the point? The unsafe features already stick out and are already keywords.

@zachaysan
Copy link

Here is an email exchange I initiated back in July when I needed to find a language to implement some code that needed to be fast and I was debating between Cython, Nim, and Go:

Hi Joseph,

I came across your comment on HN.

I want to know if you are still as enthusiastic about Nim to this day. I'm starting to get more involved in it for essentially all of the reasons you listed, but I'm worried I'll commit too early and hit some sort of wall. I need to implement a high-performance piece of infrastructure and while I'm fairly comfortable with Cython and Go, I don't especially love either of them, and I'd prefer something like Nim unless you've found consistent problems with it.

Here was his response:

Yes- still very bullish on Nim.

I can say unequivocally that it would give you some serious advantages over Go and Cython (excluding experience as a consideration).

We do a bunch of stuff in ocaml as well when we need something a little higher level (e.g., symbolic manipulation or computational proofs or safety and/or security) than Nim; although Nim could pull it off- just with more verbosity in the algebraic data types and its safety defaults (Nim has a default philosophy of nullable and mutable fields- matches system programming habits and surmountable but at the cost of some extra typing).

I seriously doubt you'll hit any kind of wall if you're going for high-performance infrastructure / real systems programming. There may be some stylistic things that bug you at first (as with any language) and some advanced features that are meaningless for some time (e.g. Effect system), and an occasional evolving (non-essential for now) language feature (like namespaces / advanced package management), but I wouldn't hesitate for a moment to recommend it from the perspective of Go and Cython, and over anything else for high-performance infra.

So I used Nim in production (calling out from Ruby, where I do most of my non-systems and non-machine code) for a performance critical piece and everything has worked out just fine.

Nim has a slower adoption curve for a couple of reasons. One is that it is so complete, that it is hard for some people to learn / justify the time commitment. The other is that it is still pre-V1, so people don't want to accept it and face breaking changes with a codebase. I haven't had any problems with nilable strings or safety, but then again, I haven't done that much with the language. I'm only a every-now-and-then user. I'm about 4x as productive with Ruby, at least half of which is because I'm so familiar with the language, but when I need to write performance critical code Nim is great.

@dom96
Copy link
Contributor Author

dom96 commented Jan 21, 2016

So what should we reply to something like this? https://news.ycombinator.com/item?id=10947761

@refi64
Copy link

refi64 commented Jan 21, 2016

My response:

In most cases, though, the GC is light enough that it can stay enabled, and you'll rarely ever end up with raw pointers.

For threading, you can use the capabilities at:

http://nim-lang.org/docs/threadpool.html

@narimiran
Copy link
Member

Now that we have not-nil seqs and strings, can we close this?

@dom96
Copy link
Contributor Author

dom96 commented Oct 8, 2018

nil is still in the language.

@narimiran
Copy link
Member

nil is still in the language.

Yes we still have nil, but in the recent discussions (in the last year or so) on HN/Reddit I haven't seen any posts like in your OP (from 3 years ago) where people are claiming Nim is unsafe and/or the Nim 'unsafety' is a deal-breaker. (Current discussions, unfortunately, are about partial case insensitivity and significant whitespace)

Of course there are still unsafe and/or dangerous parts of Nim. Or as the Quora answer said:

Nim is a systems language in the same family as C++, Rust, D, and (sort of) Go. For this family of languages, it's fairly safe.
So it's as safe as you want it to be, but no safer.

No more loud complaints about unsafety, combined with the recent not-nil seqs and strings (these were things where lots of beginners could easily trip and fall), are the reasons why I think this can be closed.

@andreaferretti
Copy link

(moreover

echo("Counting to ten: ")
for i in countup(1, 10):
  var k: ref int = nil
  var l = k[]
  echo($l)

will crash in release mode, unless you know what you are doing and take appropriate steps like disabling ASLR, and even then only on Clang)

@narimiran
Copy link
Member

will crash in release mode

That will also crash in debug mode.

@Araq
Copy link
Member

Araq commented Oct 9, 2018

I still think -d:safe vs -d:release is a good way to go.

@andreaferretti
Copy link

That will also crash in debug mode.

Yes, and it is the intended behaviour. The complaint on HN was about this snippet not crashing, due undefined behaviour and optimizations

@Araq
Copy link
Member

Araq commented Oct 9, 2018

Yes, and it is the intended behaviour. The complaint on HN was about this snippet not crashing, due undefined behaviour and optimizations

Yes and that is still a (mostly theoretical) issue until we add some C compiler specific flags to the compilation process.

@zielmicha
Copy link

-fsanitize-trap=null on clang and -fsanitize=null -fsanitize-undefined-trap-on-error on GCC are the needed flags. They don't need linking with libubsan and add only modest overhead.

@Araq
Copy link
Member

Araq commented May 11, 2020

We now have -d:release vs -d:danger, so closing. We still want -fsanitize-trap=null but I couldn't get it to work but this can be its own RFC/issue.

@Araq Araq closed this as completed May 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants