[–] 3 points 1 month ago*

The extern variadic functions are pretty cool. What I'm actually most excited about is what just moved to beta, though. In particular, stabilization of both Allocator and ! are now in beta.

  • source
  • [–] [S] 3 points 1 month ago* (3 children)

    It's a good question. I believe Vec uses a near-zero pointer but not actually a null pointer for an empty Vec. I think part of the reason is that it makes for better optimisation of Option<Vec> which can then have the same size as Vec with the pointer being null signifying None.

    Another big reason is that references are guaranteed not to be null and you can get a &[T] from an empty vec and that reference can't be null. Even in a non empty vec you need to consider this if T is zero sized.

  • source
  • parent
  • context
  • [–] 2 points 1 month ago (5 children)

    Vec::into_parts() returns a NonNull pointer, but isn’t the pointer allowed to be null if the vector is empty? I would expect that this method should be able to return a null pointer, but I’m probably missing something…

  • source
  • [–] 1 point 1 month ago (1 child)

    Their docs page just flat out doesn't work on mobile, but based on the high level descriptions of the packages, these look like something I'd install on a project without asking and write in the AGENTS.md that it's forbidden from using the more popular libraries in favor of those. (Our DS people, in general, can't and won't write code for shit, so it's the only way to get them to use a new library.)

  • source
  • parent
  • context
  • [–] 3 points 1 month ago

    This one:

    fn resize(width: u32, height: u32) {}
    fn offset(dx: u32, dy: u32) {}
    
    let f: fn(u32, u32) = if resizing { resize } else { offset };
    

    gets rewritten to something non-equivalent:

    struct Size {
        width: u32,
        height: u32,
    }
    
    fn resize(size: Size) {}
    
    // No more arguing about arguments
    let f: fn(Size) = resize;
    

    But I would say that the original idea of applying wildly different functions depending on a flag shouldn't be easily achievable, because it's a bad idea a lot of times.

  • source
  • [–] 5 points 1 month ago (3 children)

    In Python land you end up with functions with 30 arguments and when they want to pass them anywhere they give up and use kwargs which are completely awful and should almost never be used.

    Unpack[T] exists, but nobody uses it sadly. Also, it's probably better to just use a dataclass or something instead anyway, but nobody does.

  • source
  • parent
  • context
  • [–] 4 points 1 month ago

    Remember that this has no runtime cost and is fully type-safe.

    For the sake of maximal accuracy, enum size overhead can become relevant sometimes. But a work-around exists (boxing the huge variant), and with or without boxing, the performance would still beat whatever other languages have to offer.

    Otherwise, good post (I would have to say that since it mostly rehashes points I made in previous comments 😉).

  • source
  • [–] 11 points 1 month ago* (4 children)

    I agree - Structs are kind of a nicer solution here. Especially because it's pretty common to pass a whole set of options through the call stack.

    In Python land you end up with functions with 30 arguments and when they want to pass them anywhere they give up and use kwargs which are completely awful and should almost never be used.

  • source
  • [–] 3 points 1 month ago (1 child)

    Pretty interesting! This has been unstable since forever and, while it is mostly useful in more niche scenarios, it's a great addition to stable Rust.

  • source
  • [–] 4 points 1 month ago

    fearless_simd takes unsafe out of SIMD.

    No matter what level of abstraction you're after, be it autovectorization and multiversioning, or portable SIMD, or safe access to raw intrinsics and nothing more, fearless_simd has you covered!

    Just adding some context. Seems like the v1 announcement, which is cool. It looks like a really useful crate, and I'm sure I've used it transitively at least once (based on the download count), though not directly yet.

  • source
  • [–] 2 points 1 month ago

    I'd love to see a language with structural types where functions are always unary and tuples don't exist. Every function call would look like either f () (no args), f 1 (one arg) or f (foo: 1, bar: 2) (multiple args, names mandatory).

    I started building a language like this but I haven't worked on it in a while.

  • source
  • [–] 1 point 1 month ago

    Newtypes have their uses, but as a replacement for named arguments they are an overkill in many cases. They solve different problems.

    Newtypes are beneficial when some domain-specific value with an invariant is used extensively throughout the codebase. You would use them to store and pass around that value without fear that something goes wrong.

    However if we start to create a type for each parameter of every function (which may not be related at all), it would only result in a lot of unnecessary boilerplate. Named arguments is a simple and elegant solution for calling a function in a more explicit way, nothing more.

  • source
  • parent
  • context
  • [–] 7 points 1 month ago

    Who is even the target audience of this post? Beginners (which included all of us once) ask for all sorts of things. But these features didn't happen in Rust for a reason.

    Named parameters are not needed in the age of LSP hints, where this exists as an editor feature (including (neo)vim).

    But if you really want named parameters AND optionals/defaults, rust always allowed the args struct pattern:

    struct Args<'a> {
      a: &'a str,
      b: u64,
      c: Option<u64>,
    }
    
    impl<'a> Default for Args<'a> {
      fn default() -> Self {
        Self {
           a: "hi", // default
           b: 3, // default
           c: None, // optional default
        }
      }
    }
    
    takes_args(Args{a: "not hi", ..Args::default()})
    

    The builder pattern is more about valid initialization, but does interact with the arg struct pattern when you have non-default (forced) arguments, although even then, you can not use it by having:

    struct Args<'a> {
      forced_arg1: &'a str,
      forced_arg2: u8,
      defaults: DefaultArgs, // implements Default
    }
    

    So mentioning the builder pattern is out of place.

    Overloading is not used because we have traits (and the sound subset of specialization for when that's needed).

    So all in all, those "features" didn't make it to Rust not because of the backlog, or for simplicity's sake, but because idiomatic Rust (and even modern tooling in general, a la LSP) have alternatives that give you what you want and more.

    Everything mentioned above should be known by anyone who knew Rust for more than a month.

  • source
  • [–] 3 points 1 month ago

    Default/optional arguments: can be confusing when the default value is initialized.

    Yeah, which especially becomes an issue in languages with poor mutability controls. Probably the most benign variant of argument defaults would be restricting them to being const, or at the very least immutable including internal mutability. Instead we have situations like in Python where it's necessary for linters to warn people that setting [] or some other mutable data structure as a default is a bad idea (e.g. B006).

    There’s also the issue that API designers may not want their parameter names to be part of the API

    Yeah, this is also something of a mixed bag, where

    • there are some cases where having the parameter name as part of the API is desirable,
      • e.g. if some parameter position both before and after a change is a T, but it's used for different purposes,
      • though it is unclear whether that can't always be better covered by using the type system better;
    • while in most cases being locked out of doing some trivial renaming for whatever purpose (like s/blacklist/blocklist/) because it would break clients is just a PITA.

    I wrote in another comment that I was partial to named arguments out of habit, but the more I think on it, I wonder if it's not mostly a tool to work around missing type information and bad APIs, which, uh, may not be the most desirable thing to add to Rust.

  • source
  • parent
  • context
  • view more: ‹ prev next ›