Yes, that makes perfect sense regarding arrays; not sure why that did not occur to me before.
As for using structs, I should have explicitly stated that I meant them only for optional parameters. I guess I have gotten so accustomed to using them like that over the years I forget to point out that detail. And in hindsight, I guess the your commenting is still applicable for required parameters.
Lastly, and I will admit that I probably care more about this than other developers given my experience in team projects, but I actively hate it when code requires function signatures to be changed over time. Changing signatures can be disruptive in PRs and for other developers, and they can cause untold heartache when 3rd parties used packages which contain signatures you've broken.
I guess there is one caveat and that being I guess it is okay if only one developer is going to be working on the code at any one time and nobody else is going to depend on it, although I still think it is a good idea to keep in practice even on solo projects.
I do appreciate that some languages do not do a good job of making this practice practical, but whenever possible I would argue it is a best practice to code your functions with your best intention that they would never need to change their signature. BTW, I will point out that Go does a poor job of enabling this best practice given how context.Context and error are idiomatically used.
If a function has even just one optional parameter, unless by its very nature it could never need an additional optional parameter then IMO it is best to implement those parameters with a signature that won't break, be it an args struct, or (IMO, less preferable) a variadic of set funcs.
And if you need to add a new required parameter, I argue you should add an additional function with a new name to include that new parameter and leave the old function around for backward compatibility, if at all possible.
#fwiw
-Mike
P.S. One more thing. I recently came across your blog posts and subscribed. I commend you for your excellent articles, which IMO are a cut well above that which most developers are writing about programming topics. Kudos, and keep up the great work!
One thing I'd like to point out is that, you can use a single struct as an argument for a function with the "required" tag from the validator/v10 package. This approach is kinda handy for functions with numerous arguments.
Your hashtag #fwiw (for what it's worth) sums it up well. We all bring our unique experiences and biases to the table, and I appreciate you sharing yours.
Regarding my blog, thank you, Mike. I'm truly honored by your kind words. Feedback like yours motivates me to continue writing and sharing my insights with the community.
Interesting idea about the "required" tag. I can see where that would be useful for ensuring that types have required values, although I do like to minimize dependencies so unless I felt the need to use a lot of its functionality I would likely still shy away.
OTOH, it would not be hard to implement a required tag of my own and not require a dependency, so thanks; that is something for me to consider.
As for args, I have used the strategy of positional required args and optional args as structs for over well more than a decade and across numerous languages and have found it to be easy to be consistent and have never found it to fail me, so I doubt I personally would want to change to using all parameters in structs.
I do wish that Go and other languages had more bespoke functionality for dealing with required and optional parameters such as an automatic struct optional args, as well as multiple stacks for things like context.Context and error that might not be added initially but that could be discovered to be needed later. However, we do have to live in the world we've got and not in the one we only envision.
But we as both agreed on these topics, #fwiw. 🙂
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Hi Phuong,
Thank you for the answer.
Yes, that makes perfect sense regarding arrays; not sure why that did not occur to me before.
As for using structs, I should have explicitly stated that I meant them only for optional parameters. I guess I have gotten so accustomed to using them like that over the years I forget to point out that detail. And in hindsight, I guess the your commenting is still applicable for required parameters.
Lastly, and I will admit that I probably care more about this than other developers given my experience in team projects, but I actively hate it when code requires function signatures to be changed over time. Changing signatures can be disruptive in PRs and for other developers, and they can cause untold heartache when 3rd parties used packages which contain signatures you've broken.
I guess there is one caveat and that being I guess it is okay if only one developer is going to be working on the code at any one time and nobody else is going to depend on it, although I still think it is a good idea to keep in practice even on solo projects.
I do appreciate that some languages do not do a good job of making this practice practical, but whenever possible I would argue it is a best practice to code your functions with your best intention that they would never need to change their signature. BTW, I will point out that Go does a poor job of enabling this best practice given how
context.Contextanderrorare idiomatically used.If a function has even just one optional parameter, unless by its very nature it could never need an additional optional parameter then IMO it is best to implement those parameters with a signature that won't break, be it an args
struct, or (IMO, less preferable) a variadic of setfuncs.And if you need to add a new required parameter, I argue you should add an additional function with a new name to include that new parameter and leave the old function around for backward compatibility, if at all possible.
#fwiw
-Mike
P.S. One more thing. I recently came across your blog posts and subscribed. I commend you for your excellent articles, which IMO are a cut well above that which most developers are writing about programming topics. Kudos, and keep up the great work!
One thing I'd like to point out is that, you can use a single struct as an argument for a function with the "required" tag from the validator/v10 package. This approach is kinda handy for functions with numerous arguments.
Your hashtag #fwiw (for what it's worth) sums it up well. We all bring our unique experiences and biases to the table, and I appreciate you sharing yours.
Regarding my blog, thank you, Mike. I'm truly honored by your kind words. Feedback like yours motivates me to continue writing and sharing my insights with the community.
Interesting idea about the "required" tag. I can see where that would be useful for ensuring that types have required values, although I do like to minimize dependencies so unless I felt the need to use a lot of its functionality I would likely still shy away.
OTOH, it would not be hard to implement a required tag of my own and not require a dependency, so thanks; that is something for me to consider.
As for args, I have used the strategy of positional required args and optional args as structs for over well more than a decade and across numerous languages and have found it to be easy to be consistent and have never found it to fail me, so I doubt I personally would want to change to using all parameters in structs.
I do wish that Go and other languages had more bespoke functionality for dealing with required and optional parameters such as an automatic struct optional args, as well as multiple stacks for things like
context.Contextanderrorthat might not be added initially but that could be discovered to be needed later. However, we do have to live in the world we've got and not in the one we only envision.But we as both agreed on these topics, #fwiw. 🙂