On Fri, 31 May 2024 at 09:30, Al Viro <viro@xxxxxxxxxxxxxxxxxx> wrote: > > That would be something along the lines of Looks all sane to me. Putting error values in there worries me just a tiny bit, because they won't have the low bits clear, so error values will match the FDPUT_X bits, but your approach of using another type for it looks like a sane and clean model. In fact, with the different types, I think you could make things cleaner by using _Generic(), and do things like #define fd_empty(f) _Generic(f, \ struct fd: unlikely(!(f).word), \ struct fd_err: unlikely(IS_ERR((f).word)) or something like that. Untested, written in the MUA, but I think it's a good way to avoid having to remember which kind you're working with. The above obviously assumes that an 'fd_err' never contains NULL. Either it's the pointer to the fd (with whatever FDPUT_xyz bits) or it's an error value. I don't know if that was your plan. You can use similar tricks to then get the error value, ie #define fd_error(f) _Generic(f, \ struct fd: -EBADF, \ struct fd_err: PTR_ERR((f).word)) and now you can write code like if (fd_empty(x)) return fd_error(x); and it will automagically just DTRT, regardless of whether 'x' is a 'struct fd' or a 'struct fd_err'. The same model goes for 'fdput()' - don't make people have to use two names and pointlessly state the type. The bad old days where people were convinced that "Hungarian notation" was a good thing were bad. Let's leave them behind completely. Worth it? Who knows.. But I like your type-based approach, and I think that _Generic() thing would fit very very with it. Linus