• BB_C@programming.dev
    link
    fedilink
    arrow-up
    2
    ·
    19 minutes 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.

  • esa@discuss.tchncs.de
    link
    fedilink
    arrow-up
    6
    ·
    3 hours ago

    I’m used to named arguments from other languages, and that makes me fairly partial to them. Having to tool around with builders feels a lot more complex and clunky.

    That said, I do wonder at how many of the usecases aren’t workarounds for long argument lists that are either stringly typed, or something similar. As in, with a signature of (i32,i32,i32,i32) -> whatever, named arguments seem like a way of getting the compiler to catch errors in confusing {x,y}_{position,length}; but if the signature were newtypes like Rect(Origin(i32,i32), Size(i32, i32)) -> whatever, then the felt need for named arguments drops considerably.

    • anton@lemmy.blahaj.zone
      link
      fedilink
      arrow-up
      5
      ·
      1 hour ago

      With newtypes you can also emulate named args with a single struct. This also allows them to be passed on together.

      struct RectArgs{
          x:i32,
          y:32,
          w:32,
          h:32,
      }
      impl Default for RectArgs{...}
      

      Then the call site looks like this:

      rect(RectArgs{
          x:0,
          y:0,
          w:30,
          h:20,
      }
      // with default arguments
      rect(RectArgs{
          w:30,
          h:20,
          .. RectArgs::default ()
      }
      
      • esa@discuss.tchncs.de
        link
        fedilink
        arrow-up
        1
        ·
        edit-2
        18 minutes ago

        Yeah, though in those cases you might get an extra question about why rect is a function and not a method, e.g.

        Rect {
             w: 30,
             h: 20,
             .. RectArgs::default()
        }.do_the_thing()
        
  • Alavi@programming.dev
    link
    fedilink
    arrow-up
    1
    ·
    2 hours ago

    This greatly depends on language design and implementation.

    For example, Clojure has all of these and much more, and it’s still much simpler and hassle free than rust. The functions are just functions, but the forms and lists that are very powerful.

    functions are just

    (defn foo [a b] (print "do thing"))
    
    (foo 1 2)
    

    With the power of destructuring that maps provide us, we can have named arguments:

    (defn foo [a & {:keys [b c]}] (print a b c))
    
    (foo 1 {:b 2, :c 3})
    

    and for multi-arity functions, there’s no special syntax. It’s still just plain functions and forms

    (def foo
      ([a] (print "I only have one" a)
      ([a b] (print "I have two" a b)))
    

    It also has more advanced ways of polymorphysm with methods and protocols.

    It depends on the design of the language.