At one point when I was doing LD_PRELOAD stuff with Rust there was a C function I wanted to overload and couldn't (mremap, looks like), happy to see variadics finally made it in.
Sorry for repeating myself here, but it really grinds my gears....
It's not "C variadics". The compiler folks that have to work with C and C++ have for sooooo many years very clearly defined the term of art: "varargs" or "var-args". C has varargs, C++ has variadics. C varargs are dynamic, use the va_* stuff, etc. C++ variadics are instantiated at compile time.
Calling this Rust feature "C variadics" is incredibly confusing to folks who have had to work closely with both C and C++ constructs.... :sigh:
A variadic function is the accepted term of art in computer science for any function with variable arity. A C function with a variable-length argument list is an example of a variadic function. https://en.cppreference.com/c/variadic
It’s weird that C has traditionally used such sesquipedalian circumlocutions like “variable number of arguments” or “variable argument lists” rather than the usual term “variadic function”. Both K&R and the C standard avoid the common terminology. It’s not surprising that people use the much shorter pre-standard varargs.h header name instead.
(The term “variadic function” goes back to the 1960s if not further: it appears in Strachey’s “fundamental concepts in programming languages”. It’s a fairly obvious generalisation of the terms “monadic” and “diadic” that used to be common for operators, tho the non-APL world seems to have moved over to “unary” and “binary” instead. Which I guess was handy when terms from category theory became more popular…)
One thing I like about Rust is that what was valid in 1.39 is still valid in 1.99. If you like, you can update editions, which have a pretty small, bounded list of migrations (which tend to be auto-resolvable). Other than that, I mainly notice new versions when I reach for a method that used to not be available.
yeah, it’s mostly a lot of “you should check if that function you wished it had but didn’t actually exists now”, and that you should be aware of const fn. maybe that the never type stabilized? it’s mostly probably the same as you remember!
The big langage level evolutions (including standard prelude) are in the edition documents so these you should read, most of the rest is new functions / types / methods being added, they’re convenient and can unlock new capabilities but can be looked up on an ad-hoc basis or by going through types / modules as you go.
Editions aside what you used in 1.30 should work fine in 1.130.
Okay it's been a while since I did any C, but as I recall there was a difference between "varargs function" and "function that takes va_list". In particular, I saw a lot of code that defined a varargs function and called into a va_list taking function in there. Are they ABI-compatible after all?
A va_list parameter is an ordinary parameter of an implementation/ABI-defined type, so despite its relationship to varargs it doesn't require special handling in the calling convention once you've originated a va_list inside a varargs function and want to pass it on. E.g. if your libc's vprintf/vsprintf/vfprintf functions share the internal implementation (as is usually the case), say vfmt_impl, then the call from vprintf/vsprintf/vfprintf to vfmt_impl is just forward passing the va_list as a normal parameter under the ABI rules for whatever implementation-defined type it happens to be.
Yeah, that's stated in a confusing way. They're saying that it's compatible with void foo(char*, ...) but inside the function the ap: ... varargs are typed as a VaList, so it's doing the equivalent of stdarg.h's va_start implicitly at the start of the function body. The docs are clearer about this, I think: https://doc.rust-lang.org/std/ffi/struct.VaList.html
By the way, C could have done the same thing in hindsight, but as you probably know you invoke va_start on the named parameter before the ... varargs (e.g. the format parameter for printf), since the ... itself is not named in C like it is with ap: ... in the Rust example. That in turn is probably a legacy of how varargs were hacked into the earliest primeval versions of C where inside printf you'd directly access &format + n as the nth vararg slot by assuming the specific stack layout for parameter passing and relying on what we now call the default argument promotions at call sites.
There's lots of really delicious legacy stuff in C. Another fun one is open(2) being a varargs function merely so people could leave out mode in some cases for convenience.
In C23 they have made the argument to va_start() optional, and functions can be entirely varargs with no named arguments.
(There’s a weird special case undefined behaviour in the spec for va_start() if the argument is syntactically malformed, which I think ought to be a blanket caveat for all macros in the standard library – and all functions because they can all be wrapped by macros. Dunno why va_start() needs special treatment.)
junon | 11 hours ago
1.100 is going to be a banger release. Custom allocators and the never type, both highly anticipated feature.
5d22b | 3 hours ago
Part of why officially stabilizing the never type was complicated was that it already had been stably available for almost a decade. I guess that never was widely known or used.
eyesinthefire | 2 hours ago
But who's on first?
gnyeki | an hour ago
That, and dependency cooldowns (archived for posterity ahead of this merry event).
[OP] itamarst | a day ago
At one point when I was doing LD_PRELOAD stuff with Rust there was a C function I wanted to overload and couldn't (
mremap, looks like), happy to see variadics finally made it in.chandlerc | 15 hours ago
Sorry for repeating myself here, but it really grinds my gears....
It's not "C variadics". The compiler folks that have to work with C and C++ have for sooooo many years very clearly defined the term of art: "varargs" or "var-args". C has varargs, C++ has variadics. C varargs are dynamic, use the
va_*stuff, etc. C++ variadics are instantiated at compile time.Calling this Rust feature "C variadics" is incredibly confusing to folks who have had to work closely with both C and C++ constructs.... :sigh:
ghoti | 13 hours ago
A variadic function is the accepted term of art in computer science for any function with variable arity. A C function with a variable-length argument list is an example of a variadic function. https://en.cppreference.com/c/variadic
fanf | 2 hours ago
It’s weird that C has traditionally used such sesquipedalian circumlocutions like “variable number of arguments” or “variable argument lists” rather than the usual term “variadic function”. Both K&R and the C standard avoid the common terminology. It’s not surprising that people use the much shorter pre-standard varargs.h header name instead.
(The term “variadic function” goes back to the 1960s if not further: it appears in Strachey’s “fundamental concepts in programming languages”. It’s a fairly obvious generalisation of the terms “monadic” and “diadic” that used to be common for operators, tho the non-APL world seems to have moved over to “unary” and “binary” instead. Which I guess was handy when terms from category theory became more popular…)
pyj | 23 hours ago
I'm getting back into Rust and trying to figure out how to come back up to speed at missing 60 versions...
novedevo | 22 hours ago
One thing I like about Rust is that what was valid in 1.39 is still valid in 1.99. If you like, you can update editions, which have a pretty small, bounded list of migrations (which tend to be auto-resolvable). Other than that, I mainly notice new versions when I reach for a method that used to not be available.
If you're interested in seeing what's been added, I like ncameron's blogposts: https://www.ncameron.org/blog/recent-rust-changes/
lilac | 16 hours ago
yeah, it’s mostly a lot of “you should check if that function you wished it had but didn’t actually exists now”, and that you should be aware of
const fn. maybe that the never type stabilized? it’s mostly probably the same as you remember!masklinn | 12 hours ago
The big langage level evolutions (including standard prelude) are in the edition documents so these you should read, most of the rest is new functions / types / methods being added, they’re convenient and can unlock new capabilities but can be looked up on an ad-hoc basis or by going through types / modules as you go.
Editions aside what you used in 1.30 should work fine in 1.130.
muvlon | 15 hours ago
Okay it's been a while since I did any C, but as I recall there was a difference between "varargs function" and "function that takes va_list". In particular, I saw a lot of code that defined a varargs function and called into a va_list taking function in there. Are they ABI-compatible after all?
pervognsen | 12 hours ago
A va_list parameter is an ordinary parameter of an implementation/ABI-defined type, so despite its relationship to varargs it doesn't require special handling in the calling convention once you've originated a va_list inside a varargs function and want to pass it on. E.g. if your libc's vprintf/vsprintf/vfprintf functions share the internal implementation (as is usually the case), say vfmt_impl, then the call from vprintf/vsprintf/vfprintf to vfmt_impl is just forward passing the va_list as a normal parameter under the ABI rules for whatever implementation-defined type it happens to be.
muvlon | 11 hours ago
Right, that makes sense. What stumped me is this part from the Rust announcement:
So are they saying
in Rust is ABI-compatible with C
or with
?
pervognsen | 11 hours ago
Yeah, that's stated in a confusing way. They're saying that it's compatible with void foo(char*, ...) but inside the function the ap: ... varargs are typed as a VaList, so it's doing the equivalent of stdarg.h's va_start implicitly at the start of the function body. The docs are clearer about this, I think: https://doc.rust-lang.org/std/ffi/struct.VaList.html
muvlon | 11 hours ago
Oh I see, yeah that does explain it. You can just take VaList as an explicit, single arg in Rust as well. Of course.
pervognsen | 10 hours ago
By the way, C could have done the same thing in hindsight, but as you probably know you invoke va_start on the named parameter before the ... varargs (e.g. the format parameter for printf), since the ... itself is not named in C like it is with ap: ... in the Rust example. That in turn is probably a legacy of how varargs were hacked into the earliest primeval versions of C where inside printf you'd directly access &format + n as the nth vararg slot by assuming the specific stack layout for parameter passing and relying on what we now call the default argument promotions at call sites.
muvlon | 10 hours ago
There's lots of really delicious legacy stuff in C. Another fun one is
open(2)being a varargs function merely so people could leave outmodein some cases for convenience.fanf | 3 hours ago
In C23 they have made the argument to
va_start()optional, and functions can be entirely varargs with no named arguments.(There’s a weird special case undefined behaviour in the spec for
va_start()if the argument is syntactically malformed, which I think ought to be a blanket caveat for all macros in the standard library – and all functions because they can all be wrapped by macros. Dunno whyva_start()needs special treatment.)