Live data from Hacker News

Nim binary size from 160 KB to 150 Bytes

hookrace.net

41–50 of 69 posts

Re: Nim binary size from 160 KB to 150 Bytes

#41
post #19

Earlier quoted context omitted.

I agree the concept of 'non-nil' vars is very useful (and we have that in Nim), but I'm not entirely convinced by the rest of that argument. Namely, I don't agree that nil is rare enough to justify the verbosity Rust uses for it. Non-nil vars may be seen more often, but that doesn't mean nil vars aren't also often used, either. In Nim, both nil and non-nil vars are at roughly the same reach.. while in Rust non-nil va…

> Namely, I don't agree that nil is rare enough to justify the verbosity Rust uses for it. Non-nil vars may be seen more often, but that doesn't mean nil vars aren't also often used, either. It's not verbose. "Option" is 6 characters. ".map" is 4. > In Nim, both nil and non-nil vars are at roughly the same reach.. while in Rust non-nil vars are significantly easier work with. Option values are really easy to work wit…

> It's not verbose. "Option" is 6 characters. ".map" is 4.

I just want to note that verbosity isn't just about symbol length, but also about operator noise and the number of available or required commands used to achieve a goal. Just counting these characters isn't very relevant, and isn't even the best Rust can do (as someone pointed out you can use 'Some()' to get an Option var, which is only 4 chars).

That said, I agree this is rather subjective, and can't be well compared outside the context of the rest of the language.

Re: Nim binary size from 160 KB to 150 Bytes

#42
post #41

Earlier quoted context omitted.

> Namely, I don't agree that nil is rare enough to justify the verbosity Rust uses for it. Non-nil vars may be seen more often, but that doesn't mean nil vars aren't also often used, either. It's not verbose. "Option" is 6 characters. ".map" is 4. > In Nim, both nil and non-nil vars are at roughly the same reach.. while in Rust non-nil vars are significantly easier work with. Option values are really easy to work wit…

> It's not verbose. "Option" is 6 characters. ".map" is 4. I just want to note that verbosity isn't just about symbol length, but also about operator noise and the number of available or required commands used to achieve a goal. Just counting these characters isn't very relevant, and isn't even the best Rust can do (as someone pointed out you can use 'Some()' to get an Option var, which is only 4 chars). That said, I…

> (as someone pointed out you can use 'Some()' to get an Option var, which is only 4 chars)

Some() is 6 chars.

Re: Nim binary size from 160 KB to 150 Bytes

#43
post #32
post #19

Earlier quoted context omitted.

I agree the concept of 'non-nil' vars is very useful (and we have that in Nim), but I'm not entirely convinced by the rest of that argument. Namely, I don't agree that nil is rare enough to justify the verbosity Rust uses for it. Non-nil vars may be seen more often, but that doesn't mean nil vars aren't also often used, either. In Nim, both nil and non-nil vars are at roughly the same reach.. while in Rust non-nil va…

> I agree the concept of 'non-nil' vars is very useful ( non-zebra numbers[1] are also very useful. But why have a "non-zebra number" when I can just have plain numbers ? [1] A "number" which is either a number, or a zebra

...because zebra's are not a universally useful modelling tool to programmers like references are. Thus, the absence of a reference, ie nil, also becomes a useful, commonly used modeling tool. If we all wrote software using african wildlife metaphor, 'non-zebra' might then be just as useful.

Re: Nim binary size from 160 KB to 150 Bytes

#44

I like the end result. However, it makes me wonder just why it's so acceptable that simple programs like this even compile down to a 160KB executable in the first place. The actual active code is essentially some text and an interrupt. That much, at least, should be language independent. Are modern compilers incapable of discarding unreferenced code, or am I missing something?

The first compilation, which is 160 KB, is totally unoptimized, contains all kinds of debugging and checks. It's just supposed to be for yourself during development of the program.

Also there is some overhead every Nim program has. But if you get to bigger programs you'll see that Nim's binary size is just fine, for example a NES emulator is just 136 KB: http://hookrace.net/blog/porting-nes-go-nim/#comparison-of-g...

Re: Nim binary size from 160 KB to 150 Bytes

#45
post #19

Earlier quoted context omitted.

As for null in general, you can hear it from the horse's mouth here: http://www.infoq.com/presentations/Null-References-The-Billi... There are a number of ways to approach this topic, so I'll just give you one: in languages with more advanced static type systems, you try to encode as much semantic information as possible in the type. As you've said, the idea of null can be useful, so it deserves a place in the type s…

I agree the concept of 'non-nil' vars is very useful (and we have that in Nim), but I'm not entirely convinced by the rest of that argument. Namely, I don't agree that nil is rare enough to justify the verbosity Rust uses for it. Non-nil vars may be seen more often, but that doesn't mean nil vars aren't also often used, either. In Nim, both nil and non-nil vars are at roughly the same reach.. while in Rust non-nil va…

I think that 1) the vast majority of variables don't need to be nullable and 2) nullable variables are a source of common runtime errors, is a solid argument that not nullable by default is a good idea.

OCaml and Haskell don't even have the concept of null. Mutable state should be discouraged in general as it makes code harder to reason about and more buggy.

Re: Nim binary size from 160 KB to 150 Bytes

#46
post #44

I like the end result. However, it makes me wonder just why it's so acceptable that simple programs like this even compile down to a 160KB executable in the first place. The actual active code is essentially some text and an interrupt. That much, at least, should be language independent. Are modern compilers incapable of discarding unreferenced code, or am I missing something?

The first compilation, which is 160 KB, is totally unoptimized, contains all kinds of debugging and checks. It's just supposed to be for yourself during development of the program. Also there is some overhead every Nim program has. But if you get to bigger programs you'll see that Nim's binary size is just fine, for example a NES emulator is just 136 KB: http://hookrace.net/blog/porting-nes-go-nim/#comparison-of-g...

Good to know. Also, pretty cool emulator!

Re: Nim binary size from 160 KB to 150 Bytes

#47
post #36

Earlier quoted context omitted.

> Nil is a useful modelling tool, even in Rust where it exists via Option /None, correct? It's not that null is not useful. It's that most pointers can never be null, so nullability is the wrong default. And it is useful for the compiler to force you to handle the case in which pointers are null. > Perhaps by forcing you to be extremely explicit (and enforcing `match` always handles all conditions) you gain some argu…

> it is useful for the compiler to force you to handle the case in which pointers are null. Well I agree that it's very useful (and we have that in Nim), but.. > With constructs like Option::map the code is usually even less verbose than the equivalent code with null. I'm still not convinced of this part. It certainly hasn't been the case with the, admittedly small amount of, Rust code I've seen. However, I'll look f…

> Point is, nil is still a useful and commonly used tool. So the argument for verbosity and conveniences is relevant, IMO.

The only advantage of having null references is that the pattern "if this reference is null, dereference it; otherwise throw an exception" is shorter. But the question is: how often do you want that pattern? In a robust program, the answer to that is "rarely".

Put another way, it would be trivial to add sugar for the ".unwrap()" pattern to Rust (perhaps with the "!" operator) if it were necessary, gaining back the only verbosity-related advantage of null pointers. But nobody in the Rust community is asking for it. That's because this pattern is rare. If it were a problem, someone would have at least submitted an RFC by now!

> I certainly wouldn't call it "objectively" easier to reason about in a general sense.

If you write down, formally, what the star or dot operators do, there are strictly more steps involved when you have null pointers. That's why a language without null is objectively easier to reason about.

> if I have a Option reference to a mutable list in Rust, the compiler can determine weather or not the list is 'frozen' based on the runtime state of that reference?

I don't know what this means. Lifetimes rule out dangling pointers. They don't have anything to do with nullability. The borrow checker only cares about the structure of your data enough to construct loan paths.

> Can you explain this a bit?

Dereference of null is undefined behavior in C, and Nim compiles to C code that blindly dereferences pointers without inserting null checks. So dereference of null is UB in Nim too. In an earlier comment I was able to construct a Nim program that exhibited very different behavior in debug and optimized builds, using nothing but GC'd pointers.

> I did say 'rarely', and I drew a comparison to bounds-check crashes, which surely also show up in production.

Actually, Rust does try to prevent indexing-related issues by preferring iterators to raw array indexing. But, in any case, the comparison isn't relevant for a couple of reasons. First of all, in a general sense if you have big problems A and B, the fact that you can't solve B isn't an excuse to not solve A. More specifically, though, the amount of type system machinery needed to fully eliminate bounds check failures is much higher than that needed to eliminate null pointer exceptions—you basically need dependent types, whereas to eliminate null pointers all you need are bog-standard algebraic data types, which have existed since the 70s.

Re: Nim binary size from 160 KB to 150 Bytes

#48
post #41

Earlier quoted context omitted.

> It's not verbose. "Option" is 6 characters. ".map" is 4. I just want to note that verbosity isn't just about symbol length, but also about operator noise and the number of available or required commands used to achieve a goal. Just counting these characters isn't very relevant, and isn't even the best Rust can do (as someone pointed out you can use 'Some()' to get an Option var, which is only 4 chars). That said, I…

> (as someone pointed out you can use 'Some()' to get an Option var, which is only 4 chars) Some() is 6 chars.

I was measuring with pcwalton's ruler.

Re: Nim binary size from 160 KB to 150 Bytes

#49

I read this, and wonder why software has gotten so fat? Any simple application these days is easily on the few dozen of MB, most a few hundred, with a few on a few GB in size. Why aren't we streamlining software to reduce its size? I understand we have gotten "rich" on storage, but if the trend continues... I am sure many portable devices would benefit if applications were trimmed down.

My experience writing KnightOS has given me the understanding that we are wasting the obscene amount of resources available to us from modern computers.

Re: Nim binary size from 160 KB to 150 Bytes

#50
post #30

Earlier quoted context omitted.

It's not so much about "never nil" , but rather "never accidentally null" . Rust's compiler prevents you from moving data into a method which then nulls it out, leaving a dangling pointer in the calling code. At best this dangling pointer will look at garbage and cause a crash or undefined behavior. At worst, it will look at other, actively-used memory and cause a security vulnerability. Rust will just refuse to comp…

> Rust's compiler prevents you from moving data into a method which then nulls it out Just for clarity, we have this in Nim too, eg: type Foo = ref object Bar = object val: Foo not nil let f = Bar() # Error, 'val' must be set proc foobar(f: Foo not nil): Foo not nil = return nil # Error, can't return nil foobar(nil) # Error, can't pass nil > At best this dangling pointer will look at garbage and cause a crash or unde…

Out of curiosity: How do you convert from a nilable `Foo` to a `Foo not nil`? As in, what do you do if you have a function maybe returning a `Foo` and want to pass its value to a function taking `Foo not nil`?
Post reply on HN