36

While reviewing some code, I noticed the opportunity to change it to use generics. The (obfuscated) code looks like:

public void DoAllTheThings(Type typeOfTarget, object[] possibleTargets)
{
    var someProperty = typeOfTarget.GetProperty(possibleTargets[0]);
    ...
}

This code could be replaced by generics, like so:

public void DoAllTheThings<T>(object[] possibleTargets[0])
{
    var someProperty = type(T).getProperty(possibleTargets[0]);
    ...
}

In researching the benefits and shortcomings of this approach I found a term called generic abuse. See:

My question comes in two parts:

  1. Are there any benefits to moving to generics like this? (Performance? Readability?)
  2. What is Generics Abuse? And is using a generic every time there is a type parameter an abuse?
  • 2
    I'm confused. You know the name of the property beforehand but not the type of the object so you use reflection to get a value? – MetaFight Feb 7 '18 at 17:35
  • 3
    @MetaFight I know it convoluted example, the actual code would be to long and difficult to put here. Regardless, the purpose of my question is to determine if replacing the Type parameter with a generic is considered good or poor form. – SyntaxRules Feb 7 '18 at 17:39
  • 12
    I've always considered that to be the typical reason why generics exist (delicious pun not intended). Why do type trickery yourself when you can leverage your type system to do it for you? – MetaFight Feb 7 '18 at 17:42
  • 2
    your example is wierd, but I have a feeling it is exactly what a lot of IoD libraries do – Ewan Feb 7 '18 at 17:47
  • 14
    Not an answer, but it's worth noting that the second example is less flexible than the first. Making the function generic removes your ability to pass in a runtime type; Generics need to know the type at compile time. – KChaloux Feb 7 '18 at 19:34
88

When generics are appropriately applied, they remove code instead of just rearranging it. Primarily, the code that generics are best at removing is typecasts, reflection, and dynamic typing. Therefore generics abuse could be loosely defined as creating generic code without significant reduction in typecasting, reflection, or dynamic typing compared to a non-generic implementation.

In regard to your example, I would expect an appropriate use of generics to change the object[] to a T[] or similar, and avoid Type or type altogether. That might require significant refactoring elsewhere, but if using generics is appropriate in this case, it should end up simpler overall when you're done.

  • 3
    That's a great point. I'll admit the code that got me thinking of this was performing some hard to read reflection. I'll see if I can change object[] to T[]. – SyntaxRules Feb 7 '18 at 20:31
  • 3
    I like the remove vs. rearrange characterisation. – copper.hat Feb 7 '18 at 22:57
  • 13
    You missed one key use of generics - which is to reduce duplication. (Though you can reduce duplication by introducing any of those other sins you mention). If it reduces duplication without removing any typecasts, reflection, or dynamic typing IMO it is OK. – Michael Anderson Feb 8 '18 at 0:13
  • 4
    Excellent answer. I'd add that In this particular case, the OP may need to switch to an interface instead of generics. It looks as though the reflection is being used to access particular properties of the object; an interface is much better suited to allow the compiler to determine that such properties actually exist. – jpmc26 Feb 8 '18 at 2:48
  • 4
    @MichaelAnderson "remove code instead of just rearranging it" includes reducing duplication – Caleth Feb 8 '18 at 10:59
5

I would use the no-nonsense rule: Generics, like all other programming constructs, exist to solve a problem. If there is no problem to solve for generics, using them is abuse.

In the specific case of generics, they mostly exist to abstract away from concrete types, allowing code implementations for the different types to be folded together into one generic template (or whatever your language happens to call it). Now, suppose you have code that uses a type Foo. You might replace that type with a generic T, but if you only ever need that code to work with Foo, there is simply no other code with which you can fold it together. Thus, no problem exists to be solved, so the indirection of adding the generic would just serve to reduce readability.

Consequently, I'd suggest to just write the code without using generics, until you see a need to introduce them (because you need a second instantiation). Then, and only then, is the time to refactor the code to use generics. Any use before that point is abuse in my eyes.


This seems to sound a bit too pedantic, so let me remind you:
There is no rule without exceptions in programming. This rule included.

  • Interesting thoughts. However a slight rewording of your criteria could help. Suppose OP needs a new "component" that maps an int to a string and vice versa. It's very obvious that it solves a common need and could be easily reusable in the future if made generic. This case would fall in your definition of generics abuse. However, once the very generic underlying need identified, wouldn't it be worth to invest an insignificant additional effort in the design without this being an abuse ? – Christophe Feb 8 '18 at 8:07
  • @Christophe That's indeed a tricky question. Yes, there are some situations where it is indeed better to ignore my rule (there is no rule without exception in programming!). However, the specific string conversion case is actually rather involved: 1. You need to treat signed and unsigned integer types separately. 2. You need to treat float conversions separate from integer conversions. 3. You can reuse an implementation for the largest available integer types for smaller types. You may wish to pro-actively write a generic wrapper to do the casting, but the core would be without generics. – cmaster Feb 8 '18 at 10:24
  • 1
    I'd argue against pro-actively writing a generic (pre-use rather than re-use) as likely YAGNI. When you need it, then refactor. – Neil_UK Feb 8 '18 at 19:33
  • Upon writing this question I took more of the stance of "Write it as a generic if possible to save future possible reuse." I knew that was a bit extreme. It is refreshing to see your point of view here. Thanks! – SyntaxRules Feb 8 '18 at 19:44
0

The code looks odd. But if we are calling it, it looks nicer to specify the type as a generic.

https://stackoverflow.com/questions/10955579/passing-just-a-type-as-a-parameter-in-c-sharp

Personally I don't like these contortions that make the calling code look pretty. for example the whole 'fluent' thing and Extension Methods.

But you have to admit that it has a popular following. even microsoft use it in unity for example

container.RegisterType<IInterface,Concrete>()
0

To me it looks like you were on the right path here, but didn't finish the job.

Have you considered changing the object[] parameter to Func<T,object>[] for the next step?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.