[HN Gopher] N-Params vs. Single Param
___________________________________________________________________
N-Params vs. Single Param
Author : carlos-menezes
Score : 31 points
Date : 2025-04-17 18:23 UTC (4 hours ago)
(HTM) web link (www.carlos-menezes.com)
(TXT) w3m dump (www.carlos-menezes.com)
| disillusionist wrote:
| I started using this pattern years ago and haven't looked back.
| React components are defined using a single properties param and
| it feels natural to extend the practice to other methods and
| helper functions that I write.
|
| One nice unexpected side effect is that I end up with more
| consistency in variable naming when using a param object in order
| to benefit from object definition shortcuts.
|
| ie I will usually write something like const
| firstName = getFirstName(); doTheThing({ firstName });
|
| rather than const fName = getFirstName();
| doTheThing({ firstName: fName });
| carlos-menezes wrote:
| Likewise. Even if the input object only has a single property,
| I'll still use this pattern.
| disillusionist wrote:
| because i'm likely going to refactor this function "tomorrow"
| with additional properties. :)
| hyperhello wrote:
| What bothers me a lot is that return values can't have a name.
| Suppose I have a function
|
| string combineName(string first, string last);
|
| Okay, I _assume_ the result is the full name, but I don 't
| really know that like I would if the return had a name in the
| header. (The function can be getFullName, yes, but that's so
| simple it doesn't matter).
| geakstr wrote:
| Some languages allow to define type alias, name of this type
| can be self-explanatory: type FullName =
| string; function combineName(first: string, last:
| string): FullName;
|
| Also documentation comment for function is what specifically
| solves this - describes what function does and returns.
| hyperhello wrote:
| Neither really addresses the issue. Making a type for a
| single kind of string seems like an abuse of types just to
| shoehorn the documentation in. Documentation can be used
| directly of course, but that moots all of this -- just
| document? Yeah, but naming the variable is super quick
| compared to either.
| disillusionist wrote:
| you can do this rather easily by returning an object rather
| than a primitive. if you're using a language like TypeScript,
| destructuring the resulting returned object is rather trivial
| and (in my opinion) delightful to read. eg
| function combineNames({ first, last }) { const
| fullName = `${first} ${last}`; return { fullName };
| } const { fullName } = combineNames({first: 'John',
| last: 'Doe' });
| 9d wrote:
| > No guessing. No worrying about the order. Your code is self-
| documenting. Plus, TypeScript gives you full autocompletion and
| type safety.
|
| 1. Most of the time, arguments are not the same type, so if
| you're using TypeScript, you're already getting errors at this
| point. In your example, only first/last names might get mixed up.
| And if you still get those wrong while writing that code, you're
| just phoning it in atp and maybe should take a day off.
|
| 2. The same TypeScript that checks your types, also lets you see
| the signature when hovering over the function.
|
| In real world coding, this isn't an issue, and you'll probably
| give up keeping this "rule" after a year or two. But good that
| you're at least thinking about these kinds of things.
| carlos-menezes wrote:
| It's a preference grounded in long-term ergonomics that work
| well for me. I've been using this "rule" for over two years now
| and haven't found a reason to give it up.
| hwpythonner wrote:
| Not an expert in JS, but maybe this makes sense in JS where
| everything is passed as objects anyway and having a single param
| is often more readable there.
|
| But in native languages like C/C++/etc, this pattern usually
| hurts performance. Separate arguments go into registers (faster
| but depends on number of arguments), while structs often involve
| indirection, and sometimes alignment/padding issues. Also,
| passing a const struct doesn't guarantee the fields inside are
| truly const.
|
| That said, it's context dependent. If you're passing stuff
| through multiple layers or want a more stable function signature,
| using a struct can be cleaner. Just not something I'd generalize
| to any language or any use case.
| taeric wrote:
| I think the dream has long been that a compiler could optimize
| away any inefficiencies that can be mechanically described. As
| such, if there is a benefit to seeing the same structure in
| many places, using a struct would be ideal.
|
| I don't think we are near said dream, yet.
| dicytea wrote:
| Doesn't seem to be a problem, at least for Rust:
| https://godbolt.org/z/fToxz3d7a.
|
| Functions with plain arguments and a struct both produce
| identical assembly output.
| carlos-menezes wrote:
| C++ for reference: https://godbolt.org/z/7G6qxK6T8
| hwpythonner wrote:
| Try compiling with optimizations. I think by default this
| site doesn't add optimization flags.
|
| Here what happens with optimizations:
| https://godbolt.org/z/G18zd7chP
|
| Look at the registers usages vs stack
| carlos-menezes wrote:
| Got it! Thanks for the link.
| physicsguy wrote:
| If you add a third argument you get different assembly
| airstrike wrote:
| Also worth noting clippy will warn about writing functions
| with too many arguments for the same reason listed in TFA
|
| https://rust-lang.github.io/rust-
| clippy/master/index.html#to...
| the_other wrote:
| I've seen some evidence it hurts performance in JS, too. If
| you're doing something "a lot", like media qstreaming, or
| realtime updates, ordered params are likely faster.
|
| I agree with others that the destructuring is a nice syntax to
| read and write. Yet, I have started to feel it's an overused
| pattern, deployed by habit rather than consideration (in my
| code anyway). I can't put my finger on why. It's possibly a
| gut-feel that my functions would be better taking feeer
| arguments.
| tantalor wrote:
| "Avoid the Long Parameter List"
|
| https://testing.googleblog.com/2024/05/avoid-long-parameter-...
| joeyagreco wrote:
| In my opinion, this is the _only_ way to handle n-param functions
| in production code.
| sixo wrote:
| A little while ago I sketched some ideas for a programming
| language [1], one of which was that I would like a language who
| did not distinguish between these two cases. Obviously you can
| always write a function with a single N-param argument, but it's
| rather verbose, but would be nice to also be able to write the
| param list normally and then refer directly to its parameter type
| elsewhere. Although this would require that the "set of possible
| parameter lists" were the same as "the set of possible object
| type", which isn't the case in any language I know of.
|
| [1]
| https://samkrit.ch/2025/03/09/programming-1.html#anonymous-t...
| feoren wrote:
| Isn't C#'s named arguments basically what you want? You can
| choose to use the names or not at the time of calling the
| function. You can name some arguments but not others. Don't
| many programming languages have this feature?
| intrepidhero wrote:
| I had a similar thought while designing my dream programming
| language but I also wanted automatic currying and I couldn't
| figure out an ergonomic way to have both.
|
| Now I'm gonna go read your blog series.
| krystofee wrote:
| This is just because TS doesnt have keyword or keyword-only
| arguments as Python for example has.
| mx-bojangles wrote:
| I agree that the example is easier to read with the single object
| param. It might be even easier to read using a fluent interface
| or a builder pattern. You should choose the best tool for the
| job.
|
| As a counter-example, I prefer setEnabled(item,
| true);
|
| to setEnabled({item: item, isEnabled: true});
| janalsncm wrote:
| If I have five parameters and they all need to be set
| (otherwise the object is invalid), think of a constructor as a
| sort of builder pattern that does all five at once and avoids
| checking for invalid states (e.g. you only set 3 of the
| variables) in other methods.
___________________________________________________________________
(page generated 2025-04-17 23:00 UTC)