• TehPers ( TehPers@beehaw.org ) 
    link
    fedilink
    English
    arrow-up
    5
    ·
    3 days ago

    Steve doesn’t really elaborate on the drawbacks to the features he listed, just kinda says he doesn’t like them. I’ll do some of that here:

    • Function overloading: overload resolution adds a ton of complexity to the language for a feature with API-friendly workarounds (use different names, builders, etc).
    • Default/optional arguments: can be confusing when the default value is initialized. For example, in Python, default values are static and reused across calls, meaning you can technically have def foo(a=[]), append to a on each call, and use that data on future calls to foo since the same list is provided as a default each time. In C#, default values are compiled into the caller’s code, meaning if the caller’s code was developed for an older version of a library and you use it with an updated version that has a new default, the caller will still use the old default. And so on, languages all handle defaults differently.
    • Named parameters: the article covers some of the biggest issues. There’s also the issue that API designers may not want their parameter names to be part of the API (consider the function is generated by a macro or build script, for example). Also, named parameters imply to new Rust devs that the parameters can be reordered, and it’s odd to have them without optional arguments as well. Then there’s the issue of code inspection (via macro or tool) if you can reorder parameters since you can only inspect source tokens, not query semantic information, so if parameters are reordered then it can become difficult to know which value goes to which parameter from the macro/tool.
    • Varargs: to be honest, I don’t really have a drawback for this in mind beyond them just being a fair bit complicated to implement. The C# params Foo[] args equivalent wouldn’t be very useful, but varargs with variadic types would be powerful, just I assume very difficult to implement (for example fn foo<...Ts>(blahs: Ts...) or something, where Ts is a variadic tuple). In any case, that’s a feature many libraries would take advantage of (axum, bevy, etc).
    • 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.