Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How could Reflection not lead to code smells?

Tags:

reflection

I come from low level languages - C++ is the highest level I program in.

Recently I came across Reflection, and I just cannot fathom how it could be used without code smells.

The idea of inspecting a class/method/function during runtime, in my opinion, points to a flaw in design - I think most problems Reflection (tries to) solve could be used with either Polymorphism or proper use of inheritance.

Am I wrong? Do I misunderstand the concept and utility of Reflection?

I am looking for a good explanation of when to utilize Reflection where other solutions will fail or be too cumbersome to implement as well as when NOT to use it.

Please enlighten this low-level lubber.

like image 215
LiraNuna Avatar asked Feb 03 '10 22:02

LiraNuna


People also ask

How can code smells be avoided?

The best way to handle them is to just avoid them all together. If that is not possible, negotiation, documentation, and testing will make a ton of difference.

What do code smells indicate?

Put simply, code smells are a result of poor or misguided programming. These blips in the application code can often be directly traced to mistakes made by the application programmer during the coding process. Typically, code smells stem from a failure to write the code in accordance with necessary standards.

What is an example of a code smell?

For example: Comments, Duplicate Code, Lazy Class, Data Class, Dead Code, Speculative Generality. All the smells in this group contribute to excessive coupling between classes or show what happens if coupling is replaced by excessive delegation.

What is a code smell Why should it be removed?

Code Smells are not the bugs of the program. With code smells too, your program might work just fine. They do not prevent the program from functioning or are incorrect. They just signify the weakness in design and might increase the risk of bugs and program failure in the future.


1 Answers

Reflection is most commonly used to circumvent the static type system, however it also has some interesting use cases:

Let's write an ORM!

If you're familiar with NHibernate or most other ORMs, you write classes which map to tables in your database, something like this:

// used to hook into the ORMs innards public class ActiveRecordBase {     public void Save(); }  public class User : ActiveRecordBase {     public int ID { get; set; }     public string UserName { get; set; }     // ...    } 

How do you think the Save() method is written? Well, in most ORMs, the Save method doesn't know what fields are in derived classes, but it can access them using reflection.

Its wholly possible to have the same functionality in a type-safe manner, simply by requiring a user to override a method to copy fields into a datarow object, but that would result in lots of boilerplate code and bloat.

Stubs!

Rhino Mocks is a mocking framework. You pass an interface type into a method, and behind the scenes the framework will dynamically construct and instantiate a mock object implementing the interface.

Sure, a programmer could write the boilerplate code for the mock object by hand, but why would she want to if the framework will do it for her?

Metadata!

We can decorate methods with attributes (metadata), which can serve a variety of purposes:

[FilePermission(Context.AllAccess)]    // writes things to a file [Logging(LogMethod.None)]              // logger doesn't log this method [MethodAccessSecurity(Role="Admin")]   // user must be in "Admin" group to invoke method [Validation(ValidationType.NotNull, "reportName")] // throws exception if reportName is null public void RunDailyReports(string reportName) { ... } 

You need to reflect over the method to inspect the attributes. Most AOP frameworks for .NET use attributes for policy injection.

Sure, you can write the same sort of code inline, but this style is more declarative.

Let's make a dependency framework!

Many IoC containers require some degree of reflection to run properly. For example:

public class FileValidator {     public FileValidator(ILogger logger) { ... } }  // client code var validator = IoC.Resolve<FileValidator>(); 

Our IoC container will instantiate a file validator and pass an appropriate implementation of ILogger into the constructor. Which implementation? That depends on how its implemented.

Let's say that I gave the name of the assembly and class in a configuration file. The language needs to read name of the class as a string and use reflection to instantiate it.

Unless we know the implementation at compile time, there is no type-safe way to instantiate a class based on its name.

Late Binding / Duck Typing

There are all kinds of reasons why you'd want to read the properties of an object at runtime. I'd pick logging as the simplest use case -- let say you were writing a logger which accepts any object and spits out all of its properties to a file.

public static void Log(string msg, object state) { ... } 

You could override the Log method for all possible static types, or you could just use reflection to read the properties instead.

Some languages like OCaml and Scala support statically-checked duck-typing (called structural typing), but sometimes you just don't have compile-time knowledge of an objects interface.

Or as Java programmers know, sometimes the type system will get your way and require you to write all kinds of boilerplate code. There's a well-known article which describes how many design patterns are simplified with dynamic typing.

Occasionally circumventing the type system allows you to refactor your code down much further than is possible with static types, resulting in a little bit cleaner code (preferably hidden behind a programmer friendly API :) ). Many modern static languages are adopting the golden rule "static typing where possible, dynamic typing where necessary", allowing users to switch between static and dynamic code.

like image 60
Juliet Avatar answered Oct 02 '22 17:10

Juliet