Discussion: Automatic recomposition of parameter and member aggregates #2569
Unanswered
daiplusplus
asked this question in
Language Ideas
Replies: 1 comment
-
I handle this by having a Clone() member on my parameters and cloning them and then using the cloned parameters in my code. I usually have a line like this:
|
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm working on refactoring a codebase and I found myself switching between different representations of the same problem-solving code.
(By "aggregate" or "aggregation" I'm referring to an abstract collection of related values, such as the fields in a struct or a method's parameters)
Consider a service-pattern method that performs a sequence of web-service calls or database queries, it also accepts some parameters and builds an output result object.
We can start off with a version that only uses method parameters and no instance or static state:
In practice, we separate out the parameters that are likely constant throughout the program's life and move those to immutable fields that are set by the constructor, which is called by the service's factory method, usually after loading the program's configuration:
Now, supposing this is a rapidly-changing piece of code and new optional or complex method parameters are added regularly, then the method could be changed to accept a single parameter object instead. This means that consumers won't need to update their code when new parameters (as object properties) are added, this also has the benefit of allowing consumers to delegate the building of parameters to code elsewhere in their application (e.g. exposing a UI to build filter criteria) simply by passing the parameter object around:
Assuming that
GenerateCentralServicesReportAsync
uses the properties fromparas
directly instead of copying them when the method starts then the code is no-longer thread-safe as theparas
object could be modified by another thread whileGenerateCentralServicesReportAsync
runs. A solution to this is to have an immutableCentralServicesReportParameters
class along with a mutableCentralServicesReportParametersBuilder
class:Now it's getting very repetitive and violates DRY insofar as the code is having to repeat a single aggregate in multiple representations: as a builder class, as an immutable aggregate, and as the immutable aggregates constructor parameters.
Each approach obviously has its advantages and disadvantages - but I find the difficulty and hassle of switching between the different representations of the aggregate (parameters vs class properties) a bore.
With C# record types coming out, could we see new syntax for the C# compiler to take away the repetitive work of generating parameter objects and translating them to/from method parameters. Right now I do this with T4, but that's not ideal.
What I'd like to see is the C# compiler to generate record-types and/or parameter builder types using only the current C# syntax for method parameters - or perhaps a slightly different syntax so that different subsets of a method's parameters (and the immutable fields of the parent class) are exported as their own aggregates. Referring to the original stateless method from the start of this post, we define aggregate groups in the parameters using new curly braces (line-breaks added for readability):
The compiler would then convert this code into something like this in the generated assembly:
...which can then be composed into the service pattern with minimal new code and without needing to destructively refactor
CentralServicesStatic
by editing its original source code. A newAttribute
would instruct the C# compiler to treat the type being used as an aggregate and allow both the object or individual parameters to be used by hand-written consumers:The same
[ParameterAggregate]
could be used by this (human-written) wrapper to also eliminate the repetition here:Remember the C# compiler would still call
CentralServices.GenerateCentralServicesReportAsync
using real "stack" parameters and not by passing a heap-allocated parameter object. This also benefits writing test mock/stub/fake implementations by having them simply use the same named aggregates without needing to manually keep them in-sync with the real implementation despitethem being bona-fide C# method parameters:
In short: I'd like a way in C# to represent a group of values as either parameters or class/struct members without needing to repeat myself.
Beta Was this translation helpful? Give feedback.
All reactions