Live data from Hacker News

Nim binary size from 160 KB to 150 Bytes

hookrace.net

51–60 of 69 posts

Re: Nim binary size from 160 KB to 150 Bytes

#51
post #43
post #32

Earlier quoted context omitted.

> 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.

> ...because zebra's are not a universally useful modelling tool to programmers like references are.

References are not the zebras. Nil-references are.

We might as well say that the underlying number that the reference are represented by are useful modelling tools, in some circumstances. That doesn't mean that you want pointer arithmetic for references all the time.

Re: Nim binary size from 160 KB to 150 Bytes

#52
post #36

Earlier quoted context omitted.

> 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…

> there are strictly more steps involved when you have null pointers.

Well yes, and both Nim and Rust have non-nil pointers.. I suppose I misread your original statement as "Rust is objectively better ..." when you actually just said non-nil vars are an objectively better design pattern in general. My mistake.

Our argument seems to stem around the two assertions (one from you, and one from me), those are: "nil vars are be rare (in optimally written code)", and "Rust's way of working with 'nil' vars is verbose". I suppose I'll concede that non-nil vars is a better default (though I will hold reservation until I see more real statistics, I don't find "no RFC yet!" as hugely convincing), but I also feel Rust could do a better job of giving access to "nilable" vars when they're needed.

> I don't know what this means. Lifetimes rule out dangling pointers...

I mean, Rust prevents you (via compile-time mechanisms) from mutating a variable while it's borrowed by another reference.. If that reference is Option, it's only known at runtime weather or not a reference has actually borrowed said varaible. Rust must either treat every Option reference as a potential 'loan path', which would significantly diminish their usefulness as a references, encouraging indexing for these scenarios, which leads to almost identical potential for out-of-bounds crashes... or it's relying on some kind of more complex mechanism (lifetime vars maybe?).. or additional runtime overhead.

I really don't know enough about Rust to know how far off-base that is. So any clarity is appreciated.

> 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 remember this comment, but I didn't remember it achieving UB in debug code.. I'll look through the history and take another look.

Re: Nim binary size from 160 KB to 150 Bytes

#53
post #36

Earlier quoted context omitted.

> 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…

> 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.

This intrigued me so I found the comment: https://news.ycombinator.com/item?id=9050999

Re: Nim binary size from 160 KB to 150 Bytes

#54
post #52

Earlier quoted context omitted.

> 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…

> there are strictly more steps involved when you have null pointers. Well yes, and both Nim and Rust have non-nil pointers.. I suppose I misread your original statement as "Rust is objectively better ..." when you actually just said non-nil vars are an objectively better design pattern in general. My mistake. Our argument seems to stem around the two assertions (one from you, and one from me), those are: "nil vars a…

> I remember this comment, but I didn't remember it achieving UB in debug code.. I'll look through the history and take another look.

It's: https://news.ycombinator.com/item?id=9050999

Re: Nim binary size from 160 KB to 150 Bytes

#55
post #52

Earlier quoted context omitted.

> 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…

> there are strictly more steps involved when you have null pointers. Well yes, and both Nim and Rust have non-nil pointers.. I suppose I misread your original statement as "Rust is objectively better ..." when you actually just said non-nil vars are an objectively better design pattern in general. My mistake. Our argument seems to stem around the two assertions (one from you, and one from me), those are: "nil vars a…

> Rust must either treat every Option reference as a potential 'loan path', which would significantly diminish their usefulness as a references, encouraging indexing for these scenarios, which leads to almost identical potential for out-of-bounds crashes... or it's relying on some kind of more complex mechanism (lifetime vars maybe?).. or additional runtime overhead.

Can you give a concrete example of this? I'm a bit confused, but it might just be a terminology thing. In Rust, `Option` does not imply a reference. If you have a `Option` there are no references involved. An `Option` also owns the `T` if there is one. You can get a reference to it, but you have to check that it indeed holds a `T` (via `match` or `match` using functionality).

Note: I should clarify: What's confusing me is the indexing stuff. I'm not sure if this is referring to something about the `Option` or something else.

Re: Nim binary size from 160 KB to 150 Bytes

#56
post #50
post #30

Earlier quoted context omitted.

> 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`?

You prove to the compiler that the nilable var is not-nil via if statement. Eg:

  proc foobar(f:Foo not nil) =
    discard
  
  let f = Foo() # nilable ref
  let b: Foo not nil = f # Error, can't prove 'f' is not nil

  if f != nil:
    let b: Foo not nil = f # can assign non-nil vars to 'f'
    foobar(f) # or can pass 'f' directly

Re: Nim binary size from 160 KB to 150 Bytes

#57

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.

Because computers can take it and we have limited time / can be lazy? I'm just playing with a barcode reader I made that uses opencv to get the image from the camera. That's 100mb of code to do something you could probably do with <1 mb but it makes things easy and works.

Re: Nim binary size from 160 KB to 150 Bytes

#58
post #52

Earlier quoted context omitted.

> there are strictly more steps involved when you have null pointers. Well yes, and both Nim and Rust have non-nil pointers.. I suppose I misread your original statement as "Rust is objectively better ..." when you actually just said non-nil vars are an objectively better design pattern in general. My mistake. Our argument seems to stem around the two assertions (one from you, and one from me), those are: "nil vars a…

> I remember this comment, but I didn't remember it achieving UB in debug code.. I'll look through the history and take another look. It's: https://news.ycombinator.com/item?id=9050999

So I remembered correctly, Nim does not reach UB in non-release code (or rather, code without --boundCheck:on), it throws an exception. I still think this is a reasonable solution. We catch these errors during development iteration or enable it for safety-critical portions of release code (or the entire project).. and we can opt-out of these checks if we need the performance and safety isn't as important (games, simulations, etc).

I remember Rust does not bounds-check it's iterators, so you don't need to really disable bounds-checks (indeed, you cannot) while Nim, currently, does this more niavely and looses some performance for it. That's a nice thing Rust does, but not something Nim can't eventually catch up too. See this comparison for futher reference: http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs...

Re: Nim binary size from 160 KB to 150 Bytes

#59
post #58

Earlier quoted context omitted.

> I remember this comment, but I didn't remember it achieving UB in debug code.. I'll look through the history and take another look. It's: https://news.ycombinator.com/item?id=9050999

So I remembered correctly, Nim does not reach UB in non-release code (or rather, code without --boundCheck:on), it throws an exception. I still think this is a reasonable solution. We catch these errors during development iteration or enable it for safety-critical portions of release code (or the entire project).. and we can opt-out of these checks if we need the performance and safety isn't as important (games, simu…

> So I remembered correctly, Nim does not reach UB in non-release code (or rather, code without --boundCheck:on), it throws an exception.

That's not really correct. It's undefined behavior either way; you're just getting lucky because the compiler doesn't happen to take advantage of the undefined behavior to perform optimizations at -O0.

Re: Nim binary size from 160 KB to 150 Bytes

#60
post #56
post #50

Earlier quoted context omitted.

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`?

You prove to the compiler that the nilable var is not-nil via if statement. Eg: proc foobar(f:Foo not nil) = discard let f = Foo() # nilable ref let b: Foo not nil = f # Error, can't prove 'f' is not nil if f != nil: let b: Foo not nil = f # can assign non-nil vars to 'f' foobar(f) # or can pass 'f' directly

Ah, good to know. So Nim does static analysis on conditionals where Rust would use an explicit pattern match to get at the contained value.

Might be a good example for http://nim-lang.org/manual.html#not-nil-annotation

Post reply on HN