4

Is it a bad idea to add a new method (that implements a new algorithm) to a class library for its new version and expose a version option the consumers can select?

It is just for backward compatibility where an old application might need a constant sequence of random numbers for a certain seed number.

The following code might speak my idea much better. Hopefully you get the essence.

//Class Library:
namespace MyGenerator
{
    public sealed class MyRandom
    {
        public enum Version { One, Two }// add more options in the future 
        private int current;
        private Version version;

        public MyRandom(int seed, Version version = Version.One)
        {
            current = seed;
            this.version = version;
        }

        public int Next()
        {
            switch (version)
            {
                case Version.One:
                    AlgorithmOne();
                    break;
                case Version.Two:
                    AlgorithmTwo();
                    break;
                // add more options in the future
            }
            return current;
        }

        private int AlgorithmOne()
        {
            current = (current * 1234567890 + 987654321) & 0x7FFFFFFF;
            return current;
        }

        private int AlgorithmTwo()
        {
            current = (current * current + current) & 0x7FFFFFFF;
            return current;
        }
        // add more algorithm in the future
    }
}

and

//Console Application (for testing purposes):

using MyGenerator;
using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            const int seed = 12345;
            MyRandom rnd = new MyRandom(seed, MyRandom.Version.Two);
            Console.WriteLine(rnd.Next());
            Console.ReadLine();
        }
    }
}
11

No, never do this. If you want to design for future versionability then use the object-oriented patterns specifically designed for that. For example, here's how I would solve your problem:

abstract class MyRandom
{
    // Ensure that a third party cannot extend the base
    // class by making the ctor private.
    private MyRandom() {}

    public abstract int Next();

    private class First : MyRandom
    {
        // whatever
    } 

    private class Second : MyRandom
    {
        // whatever
    } 

    // Chef's choice:
    public static MyRandom MakeRandom() { return new Second(); }

    // Diner's choice:
    public static MyRandom MakeFirst() { return new First(); }
    public static MyRandom MakeSecond() { return new Second(); }
}

When you want to add a new version, that's a private implementation detail of the class, and you then add a new static factory method. If the caller wants you to choose the best version, they call the method that lets you decide. If they have a specific version they want, they call a method that gives them that.

Some more guidance:

  • If you believe you will be adding more members to an enum in the future then you are probably doing something wrong. The set of items in an enum should be identical forever.

  • If you are taking a non-flags enum with n options and doing n different things as a result then just write n methods.

  • Sorry, is there a simple example to show how bad the idea of progressively adding members to an enum across versions is? – kiss my armpit Jan 3 '14 at 17:38
  • 3
    @StiffJokes: Yes: the code you already wrote. Suppose your customer writes that same switch statement. Now you add a new member to the enum and they recompile their code. What magic causes them to know that they need to update their switch statement to handle a new element? Either you've forced them to do work, which is bad, or they don't know that they have to do the work, which is worse. Enums that change over time cause your customers to write time bombs that explode years later. Don't hand a bomb to your customers. – Eric Lippert Jan 3 '14 at 17:40
  • 3
    @StiffJokes: What this illustrates is that your enum is an implementation detail of your class, but you then not only expose that implementation detail, you require that the customer know about it! The whole point of keeping implementation details private is so that you can change them without breaking customers. – Eric Lippert Jan 3 '14 at 17:42
  • I see. It makes sense when considering the customers who will use my code. I did not think of it as I am the only person using my code. Thank you. – kiss my armpit Jan 3 '14 at 17:48
  • 2
    @StifJokes: Eric's example utilizes the abstract factory pattern (en.wikipedia.org/wiki/Abstract_factory_pattern). Also, the objective you're trying to accomplish also aligns well with the Strategy Pattern (en.wikipedia.org/wiki/Strategy_pattern). The advantage of using these patterns is you can dynamically provide the correct algorithm in a non-breaking backwards compatible way, while isolating the version-specific implementation of your algorithm in the code for that version. – M. Smith Jan 3 '14 at 17:56
10

Having a version parameter would be dirty.

It's a blatant mixing of concerns. The first concern is what the method is expected to do. The second concern how to manage multiple conflicting versions of a massive API. The two are completely unrelated and should stay as separate as possible.

As a developer, I'm only interested in the first concern (what the method is expected to do). If I try to call Math.Random and suddenly there's a parameter for version... well, I'll be confused. What does versioning have to do with randomness?

In other words, adding a version parameter would force the developer to become aware of the implementation of Math.Random (and its history) instead of just knowing what it's expected to do. In my opinion, that would make it a very bad API.

  • It is only true if the PRNG must be ideal such that it produces a different sequence of numbers for the same seed. The current implementation of Random will produce the same sequence of numbers for the same seed. If Microsoft wants to keep the latter behavior (as it cannot create the ideal PRNG in the former), my method should be a good idea I think. What do you think? – kiss my armpit Jan 3 '14 at 15:14
  • @StiffJokes yes, but the parameter that selects which implementation is a bad idea - better to add a new method (or entire class if necessary) – gbjbaanb Jan 3 '14 at 16:40
4

The likely answer is... because they don't want to.

Sounds like they are leaving their option open to switch to a different PRNG algorithm if a new one they prefer was to come along. There's also the possibility that future .NET runtimes for entirely new platforms may require something different in terms of a PRNG algorithm, so they don't want to lock themselves into a certain algorithm.

They don't need to provide prior versions of their generators because they are flat out telling you not to rely on it for predictable results. The purpose is to return a psuedo-random number. Not a reproducible sequence of numbers. There is no reason to ever care what version of algorithm they are using, because you are calling it to get a random number.

If you need predictable results, you should implement your own random number generator (preferably using one of the better tested, known algorithms).

  • It is not the answer I am looking for. See my edited question. – kiss my armpit Jan 3 '14 at 4:47
2

It's an interesting idea. However, I would probably curse the library developer when I try to use a method like this. From user perspective, it makes the library much more complicated to understand.

In this specific case, I will go for the Template Method pattern. I will create an abstract class "Random" and make the existing "MyRandom" its subclass.

After this, I can implement algorithm B in another new subclass ("YourRandom", "HisRandom" :) ) The existing code will not break, new usage can select the algorithm for random.

  • I don't think it will be complicated for the users as the changes will rarely occur I think. – kiss my armpit Jan 3 '14 at 15:35

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.