10

Imagine a situation where we're using a library that allows you to create Circle objects, where you can specify the radius and the center of the circle to define it. However, for some reason, it also takes a required flavour parameter. Now let's say I really need to use Circle in my own app, but for the purposes of my app I can set the flavour to be Flavours.Cardboard every single time.

To "solve" this, I create my own Circle class in a different namespace, which only takes radius and center as parameters, but has an implicit converter to the external library's Circle class which just creates a Circle(this.radius, this.center, Flavours.Cardboard) object. So everywhere I need the other type of Circle, I let the automatic conversion take place.

What are the consequences of creating such a class? Are there any better solutions? Would it make any difference if my application was an API built on top of this external library, intended for use by other programmers?

  • This seems like a variation of the Adapter Pattern, though it seems to be of dubious value here (it being merely a convenience for avoiding setting a parameter). – Robert Harvey May 28 '16 at 4:04
  • 5
    Why not create a MakeCircle function? – immibis May 28 '16 at 6:12
  • 1
    @immibis Thay was my first thought. When I'm making games, I'll often create a function along the lines of makePlayer that itself only accepts coords to place the player at, but delegates to a much more complex constructor. – Carcigenicate May 28 '16 at 12:40
13

While it isn't always bad, it is pretty rare that implicit conversions are your best option.

There are issues.

  1. Implicit conversions are not very readable.
  2. Because you're making a new object, any changes to the original object won't be seen by the one you're converting to, leading to bugs.
  3. If you're throwing the object away, that's extra garbage to clean up.
  4. If there is a problem, it will happen when the conversion occurs, not when the thing is created, making bugs that are harder to track down.

In general, there are better solutions.

  1. Make your own thin wrapper that's uses the other class/framework internally.
  2. Make a helper method that takes the constuctor arguments you want and supplies the one that is fixed, returning the real object without having to specify the argument you don't care about.
  3. Inherit from the problem class and supply your own, nicer constructor.
  4. Realize that passing in the extra argument really isn't that big of a deal.

Personally, I find #2 to be the simplest to implement, and the least burdensome on the design. The others can be fine, given the situation and what else you're trying to do with these classes.

The implicit conversion is a last resort, and only really seems worth it to me when I have C++ style functors I'm trying to make - strategy objects I implicitly convert to delegate types.

1

Given the scenario you are describing, you can think of this in terms of partial function application.

A constructor is a function (at least in theory; in C#, you can create a "factory function" that calls the constructor):

Func<double, Point, Flavour, Circle> MakeCircle = (r, p, f) => new Circle(r, p, f);

for partial application, the following will suffice:

public static Func<T1, T2, R> Partial<T1, T2, T3, R>(this Func<T1, T2, T3, R> func, T3 t3)
   => (t1, t2) => func(t1, t2, t3);

You can now get your constructor that only requires 2 parameters:

Func<double, Point, Circle> MakeCardboardCircle = Circle.Partial(Flavours.Cardboard)

So now you have a factory function with your desired parameters

Circle c = MakeCardboardCircle(1.0, new Point(0, 0)))

BTW, this is clearly equivalent to option 2 above, just from a more functional perspective.

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.