views:

116

answers:

2

UPDATE The main questions remain the ones under the example, but I guess it boils down to :

**If you have a type where 99% of the values could be represented in one fast, powerfull type, and only 1% in a very heavy type, (say int vs. BigInteger) How to represent it?? **

A school we learned a lot about internal representations, but never how to change it at runtime. I mean : suppose you have a class representing a decimal, but you use an integer to represent it internal, until you actually need a bigger value than the integer, and only than change representation...

I never thought of this before, and when thinkihng of it, I thought that would never work, since all the checks would kill it. But I just did a test since I'm too curious for my own good and there do exist situations when changing of representation is more perormant : given this interface :

interface INumber
    {
        void add1000();
        void SetValue(decimal d);
        decimal GetValue();                     
    }

I found the latter of the two implementations to be more powerful in a lot of situations, including this one that I composed to attract as many ideas I could on the matter (not rep, it's community)

    1. Representation by only a decimal

        public class Number1:INumber
        {

         private decimal d { get; set; }


         public void add1000()
         {
          d += 1000;
         }



         public decimal GetValue()
         {
          return d;
         }



         public void SetValue(decimal d)
         {
          this.d = d;
         }

        }


2. Representation by a decimal and an int

public class Number2:INumber
    {
     private bool usedecimal; 
     private int i;
     private decimal d;

     public void add1000()
     {
      if (usedecimal)
      {
       d += 1000;
       return; 
      }

      i += 1000;

      if (i > 2147480000)
      {
       d = i;    
       usedecimal = true;    
      }


     }

     public void SetValue(decimal d)
     {
      try
      {
       i = (int)d;

      }
      catch (OverflowException e)
      {

       this.d = d;
      }

     }

     public decimal GetValue()
     {
      return Math.Max(i,d);
     }
    }
}

My question is the following :

This seems sth. I have been missing, but this must be the bleeding obvious. Can anyone help me out with this?

  • Are there guidelines for mixed representations, when to use them, when not?
  • How to have a hunch when a mixed represtenation can be faster without benchmarking?
  • Any examples?
  • Any patterns?
  • Any ideas on the matter?
A: 

Perhaps you're looking for the Bridge pattern.

Joel Lucsy
+7  A: 

If you have a type where 99% of the values could be represented in one fast, powerfull type, and only 1% in a very heavy type, (say int vs. BigInteger) How to represent it??

BigInteger implementations typically do exactly that; they keep everything in ints or longs until something overflows, and only then do they go to the heavierweight implementation.

There's any number of ways to represent it. A pattern I like is:

public abstract class Thing
{
    private class LightThing : Thing
    { ... }
    private class HeavyThing : Thing 
    { ... }
    public static Thing MakeThing(whatever) 
    { /* make a heavy or light thing, depending */ }
    ... etc ...
}

Are there guidelines for mixed representations, when to use them, when not?

Sure. We can easily compile such a list. This technique makes sense if:

(1) the lightweight implementation is much lighter than the heavyweight implementation

(2) the typical usage falls into the lightweight code path most of the time

(3) the cost of detecting the transition is not a significant cost compared to the cost of the heavyweight solution

(4) the more complex two-representation solution is necessary in order to achieve a customer-focused, realistic performance goal.

How to have a hunch when a mixed represtenation can be faster without benchmarking?

Don't. Making performance decisions based on hunches is reasoning in advance of facts. Drive performance decisions on realistic, customer focused, data-driven analysis, not on hunches. If I've learned one thing about performance analysis over the years its that my hunches are usually wrong.

Any examples?

Any number of implementations of BigInteger.

Any patterns?

Beats the heck out of me. I'm not much of one for memorizing pattern taxonomies.

Any ideas on the matter?

See above.

Eric Lippert
This is an excellent example of how to implement such a system; the factory pattern (being used with, I'm assuming, an immutable class) is a better pattern to follow than "changing the internal representation at runtime". It may seem like a semantic difference, since it is doing the same thing *in effect*, but this seems to be a much cleaner way of doing things.
Adam Robinson