Live data from Hacker News

Passing nothing is surprisingly difficult

davidben.net

41–50 of 80 posts

Re: Passing nothing is surprisingly difficult

#41

Earlier quoted context omitted.

> Programs written to the C99 standard can resize a dynamic vector down to empty with a resize(ptr, 0). C99 has no resize() function. Assuming you mean realloc(), C99 does not guarantee you can use realloc() in this manner. See also: https://news.ycombinator.com/item?id=38850575 https://stackoverflow.com/questions/16759849/using-realloc-x... https://wiki.sei.cmu.edu/confluence/plugins/servlet/mobile?c... https://deve…

Indeed, you couldn't reliably free() the old pointer if the realloc(ptr, 0) failed. But xrealloc(ptr, 0) (or equivalent) would still be perfectly consistent, assuming you trust your implementation to support non-null 0-size allocations in the first place. It's very common to just "leak it all and abort" on a critical error like memory exhaustion. There's a reason most non-C languages expose an infallible allocation A…

Yes. If realloc(ptr, 0) returns a null pointer, you don't know whether that's due to a failure (in which case ptr is still valid) or whether it's the happy case (ptr was freed, and the zero-sized request for replacing it produced a null). Thus you don't know whether ptr is still a valid pointer. If it's valid and you treat it as invalid (hands off), that's a leak. If it's invalid and you treat it as valid (free it), that's a double free.

Re: Passing nothing is surprisingly difficult

#42

How does zig handle this? Does it just have its own slice representation that gets compiled away? Or does it disallow zero length slices?

Zig slices are (start, count) where start's type is non-nullable pointer.

My impression is that Zig doesn't have a documented memory model that cares about things like whether an address corresponds to an allocation or not, so problems relating to this sort of thing cannot come up yet :)

Re: Passing nothing is surprisingly difficult

#44

How does zig handle this? Does it just have its own slice representation that gets compiled away? Or does it disallow zero length slices?

I am not entirely sure, but it seems they chose to return a null pointer:

https://github.com/ziglang/zig/commit/32e0dfd4f0dab351a024e7...

Re: Passing nothing is surprisingly difficult

#45
post #44

How does zig handle this? Does it just have its own slice representation that gets compiled away? Or does it disallow zero length slices?

I am not entirely sure, but it seems they chose to return a null pointer: https://github.com/ziglang/zig/commit/32e0dfd4f0dab351a024e7...

This is a commit that changes the now-defunct Zig compiler written in C++ to be careful when it calls malloc. So it has nothing to do with the semantics of the Zig language or the compatibility of zero-sized Zig slices with Rust, C, or C++ APIs.

Re: Passing nothing is surprisingly difficult

#46
It's obviously too late to change this in Rust's case, but I wonder whether being able to differentiate between None and the empty slice is actually a necessary property in general?

There are a bunch of languages where empty arrays are "falsy", and in those it's not recommendable to use the two to differentiate valid states. Feels like the same could apply here

Re: Passing nothing is surprisingly difficult

#47

It's obviously too late to change this in Rust's case, but I wonder whether being able to differentiate between None and the empty slice is actually a necessary property in general? There are a bunch of languages where empty arrays are "falsy", and in those it's not recommendable to use the two to differentiate valid states. Feels like the same could apply here

Unfortunately empty slices are pretty useful, particularly for strings. For example, if you want to represent HTTP response headers, you might include a bunch of nigh-ubiquitous headers in a struct and punt the others to a hash table, and you would then have to represent both empty-valued-and-present headers and missing headers for those headers you placed in the struct.

Re: Passing nothing is surprisingly difficult

#49

There is no problem with memcpy other than that you can't use a null pointer. You can memcpy zero bytes as long as the pointer is valid. This works in a good many circumstances; just not circumstances where the empty array is represented by not having an address at all. For instance, say we write a function that rotates an array: it moves the low M bytes to the top of the array, and shuffles the remaining M - N bytes…

[deleted]

Re: Passing nothing is surprisingly difficult

#50
post #33

Earlier quoted context omitted.

The BSD people don't understand what little standards they do read. It's unfortunate that we have to spoil the language for their sake. The requirements in C99 and before are perfectly clear. realloc is described as liberating the old pointer, and then allocates a new one as if by malloc. (Except that it magically has access to both objects so it can transfer the necessary bytes that must be transferred from the old…

Just a reminder to myself how happy I am to leave this academic level of snobbery behind and migrate to languages that help getting things done and save you from nonsense like this. I did C for about ten years. Hope I’ll never have to do a single line of it again.

> this academic level of snobbery

...is actually very uncommon in the C world (at least much less common than in the C++ or Rust world).

Specific compilers and stdlibs have specific behaviours which may or may not fully agree with the details written down in the standard. You'll have to pick a subset of compilers you want to support and write your code against that subset of compilers. It's not perfect, but also not much of a problem. It's simply the reality when there are multiple compiler implementations.

Post reply on HN