Infinite types in C#? (or maybe a better implementation)

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Prelates, Moderators General

Infinite types in C#? (or maybe a better implementation)

Postby ineon » Tue Jan 31, 2012 12:06 pm UTC

In a project that I am doing I have a family of classes that are always used in conjunction with each other. Each of these classes in the family have subclasses that also fall into a family.

The examples below uses cars and engines to demonstrate the point. There is one family of base class cars and subclasses of fuel cars (sorry in advance that I am too English and refuse to call it gas - it is a liquid after all). At a later point we may want to add other families of cars, for example electric cars, steam powered cars, cold fusion cars...

The problem is that a fuel car will always use a fuel engine (and vice versa) but each time I have to explicitly upcast.

Code: Select all
   class Car
   {
      public Engine Engine { get; set; }
   }

   class Engine
   {
      public Car Car { get; set; }
   }

   class FuelCar : Car
   {
      
   }

   class FuelEngine : Engine
   {
      public bool HasFuel()
      {
         return true;
      }
   }

   class Program
   {
      public static void Main1()
      {
         FuelCar car = new FuelCar();
         FuelEngine engine = new FuelEngine();

         car.Engine = engine;
         engine.Car = car;

         ((FuelEngine)car.Engine).HasFuel();
      }
   }


I would ideally like to remove that (FuelEngine) cast.

One implementation is to create a new property on the inheriting classes.

Code: Select all
   class Car
   {
      private Engine engine;
      public Engine Engine
      {
         get { return engine; }
         set
         {
            Validate(value);
            engine = value;
         }
      }

      protected virtual void Validate(Engine value)
      {
         // do nothing
      }
   }

   class Engine
   {
      private Car car;
      public Car Car
      {
         get { return car; }
         set
         {
            Validate(value);
            car = value;
         }
      }

      protected virtual void Validate(Car value)
      {
         // do nothing
      }
   }

   class FuelCar : Car
   {
      public new FuelEngine Engine
      {
         get { return base.Engine as FuelEngine; }
         set { base.Engine = value; }
      }

      protected override void Validate(Engine value)
      {
         if (!(value is FuelEngine)) {
            throw new ArgumentException();
         }
      }
   }

   class FuelEngine : Engine
   {
      public new FuelCar Car
      {
         get { return base.Car as FuelCar; }
         set { base.Car = value; }
      }

      protected override void Validate(Car value)
      {
         if (!(value is FuelCar)) {
            throw new ArgumentException();
         }
      }

      public bool HasFuel()
      {
         return true;
      }
   }

   class Program
   {
      public static void Main2()
      {
         FuelCar car = new FuelCar();
         FuelEngine engine = new FuelEngine();

         car.Engine = engine;
         engine.Car = car;

         car.Engine.HasFuel();
      }
   }


This has the advantage that all the casting is all done in one place. However, it has now become more verbose. It is also not quite as elegant as the other solution below.

I wanted to try with generics to get rid of this verbosity and the casting altogether.
Code: Select all
   class PowerType { }
   class Fuel : PowerType { }

   class Car<TPower, TEngine> where TPower : PowerType where TEngine : Engine<TPower, Car]>
   {
      public TEngine Engine { get; set; }
   }

   class Engine<TPower, TCar> where TPower : PowerType where TCar : Car<TPower, Engine>
   {
      public TCar Car { get; set; }
   }

   class FuelCar : Car<Fuel, FuelEngine>
   {

   }

   class FuelEngine : Engine<Fuel, FuelCar>
   {
      public bool HasFuel()
      {
         return true;
      }
   }

   class Program
   {
      public static void Main3()
      {
         FuelCar car = new FuelCar();
         FuelEngine engine = new FuelEngine();

         car.Engine = engine;
         engine.Car = car;

         car.Engine.HasFuel();
      }
   }


The types would all work without any casting - each Car knows what type of Engine it has, and each Engine know what type of Car it is part of. HOWEVER the types of TCar and TEngine are recursive and type gets infinite. The full type would be of the form:
Code: Select all
TEngine : Engine<TPower, Car<TPower, Engine<TPower, Car<TPower, ...>>>>


Is there a way to collapse the infinite type into a finite type? Or is there a sensible way of creating this family of classes that doesn't rely on infinite types?

Thanks.
ineon
 
Posts: 7
Joined: Tue Jan 31, 2012 11:23 am UTC

Re: Infinite types in C#? (or maybe a better implementation)

Postby Xeio » Wed Feb 01, 2012 1:40 am UTC

You probably shouldn't have Engine refer to a Car. Generally if two classes have instances of each other, there is probably a better design pattern.

I'm hesitant to try and suggest changing the pattern you're using, because this sounds like some arbitrary homework example of inheritance and you don't seem to have an actual design, just classes you're trying to hook together. But some things to consider:

Why do you need engine to refer to a car?
Why doesn't an engine have a HasFuel by default? Are there engines that can run without some sort of fuel (or energy source as it were)?
Why doesn't the car know if it has fuel? It has the gas tank after all.
Are there actually going to be other types of cars? Do you really need to use inheritance here for fuel specific ones?
User avatar
Xeio
Friends, Faidites, Countrymen
 
Posts: 4865
Joined: Wed Jul 25, 2007 11:12 am UTC
Location: C:\Users\Xeio\

Re: Infinite types in C#? (or maybe a better implementation)

Postby ineon » Wed Feb 01, 2012 10:59 am UTC

Thanks for your questions. I am afraid that I've already asked those questions that you have asked. I'm not actually doing a car problem, but I thought that it would demonstrate the problem that I am facing. I am working on a report generation tool. The different 'families' are different data sources which have different connection requirements, different security models, different date formats etc.

I agree that there is probably a better design, such that if X has a reference to Y then Y should not have a reference to X, but I have got to work with what I am given.

To partially answer my own question (in case anyone else is interested) you can add a third type variable to the signature to make it compile properly.
Code: Select all
   class Car<TPower, TEngine, TCar>
      where TPower : PowerType
      where TEngine : Engine<TPower, TCar, TEngine>
      where TCar : Car<TPower, TEngine, TCar>
   {
      public TEngine Engine { get; set; }
   }

   class Engine<TPower, TCar, TEngine>
      where TPower : PowerType
      where TCar : Car<TPower, TEngine, TCar>
      where TEngine : Engine<TPower, TCar, TEngine>
   {
      public TCar Car { get; set; }
   }

   class FuelCar : Car<Fuel, FuelEngine, FuelCar>
   {

   }

   class FuelEngine : Engine<Fuel, FuelCar, FuelEngine>
   {
      public bool HasFuel()
      {
         return true;
      }
   }
class AddSecondType
   {
      public static void Main2()
      {
         FuelCar car = new FuelCar();
         FuelEngine engine = new FuelEngine();

         car.Engine = engine;
         engine.Car = car;

         car.Engine.HasFuel();
      }
   }

   class PowerType { }
   class Fuel : PowerType { }

It avoids the infinite type problem by using a type variable in its own definition. So TCar: Car<TPower, TEngine, TCar>. It the downside to this implementation is that I cannot currently work out a type T such that the following code compiles and T is more specific than object.
Code: Select all
T baseCar = new FuelCar();
baseCar = new ElectricCar();
ineon
 
Posts: 7
Joined: Tue Jan 31, 2012 11:23 am UTC

Re: Infinite types in C#? (or maybe a better implementation)

Postby Sc4Freak » Wed Feb 01, 2012 12:13 pm UTC

For future reference, this is pattern is typically referred to as the "curiously recurring template pattern". It was originally a C++ pattern but applies equally well to C# generics.

It the downside to this implementation is that I cannot currently work out a type T such that the following code compiles and T is more specific than object.


The typical way to solve that is to abstract out as much as you can into an interface. That is, have a non-generic interface ICar which contains all the methods and properties in Car<TPower, TEngine, TCar> which are invariant on the generic parameters, and have Car implement that interface. For example, a Car<TPower, TEngine, TCar> might have a MilesPerGallon property whose type doesn't depend on any of its generic parameters - you can abstract that out into the ICar interface.
User avatar
Sc4Freak
 
Posts: 673
Joined: Thu Jul 12, 2007 4:50 am UTC
Location: Redmond, Washington

Re: Infinite types in C#? (or maybe a better implementation)

Postby Webzter » Wed Feb 01, 2012 4:20 pm UTC

I looked at shamelessly abusing dynamic, subclassing DynamicObject (with some custom code in the type resolvers), and generally doing nonsensical things with extension methods... I certainly wouldn't call the results prettier, though. All code was subsequently burned and will never be spoken of again.
Webzter
 
Posts: 179
Joined: Tue Dec 04, 2007 4:16 pm UTC
Location: Michigan, USA

Re: Infinite types in C#? (or maybe a better implementation)

Postby Yakk » Wed Feb 01, 2012 5:01 pm UTC

A general problem with the "typical" object model is that mutable objects don't have reasonable object inheritance models that actually work.

A mutable fuel car is not a type of car, because cars accept kinds of engines that fuel cars do not. On the "writing" side, your petrol car is a restriction of car: there are writing operations on cars that are not valid on petrol cars. On the other hand, every reading operation on a car is also valid on a petrol car -- while there are reading operations on petrol cars that are not valid on cars.

With an immutable car, the immutable petrol car is indeed a subclass (it supports everything the car does, plus extra).

A petrol car factory or manufacturing class does not have the same relationship to a car factory or manufacturing class. The standard C++/C#/Java inheritance mechanisms really don't help you much here.

The CRTP only uses the object model to generate implementation details, rather than providing a class interface inheritance. You get some ducktype relationships between the classes, but little to no class relationships between the classes.

Generally, falling in love with immutable objects is a fun thing to do at least once. :)
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
Poster with most posts but no title.
 
Posts: 10491
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Infinite types in C#? (or maybe a better implementation)

Postby WarDaft » Thu Feb 02, 2012 12:54 am UTC

Generally, falling in love with immutable objects is a fun thing to do at least once.
I've rather wondered... is there any real difference between an immutable object and an algebraic data type, aside from possibly an ADT being more flexible?
All Shadow priest spells that deal Fire damage now appear green.
Big freaky cereal boxes of death.
User avatar
WarDaft
 
Posts: 1577
Joined: Thu Jul 30, 2009 3:16 pm UTC

Re: Infinite types in C#? (or maybe a better implementation)

Postby Yakk » Thu Feb 02, 2012 4:05 am UTC

ADTs are an example of an immutable object? It does not change from construction to destruction. This is true of everything in a purely functional language. You could probably make a non immutable ADT like structure with some of its properties in a non functional language as well...
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.
User avatar
Yakk
Poster with most posts but no title.
 
Posts: 10491
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Infinite types in C#? (or maybe a better implementation)

Postby ineon » Thu Feb 02, 2012 9:20 am UTC

On the "writing" side, your petrol car is a restriction of car


Thanks Yakk, you have hit the nail on the head with that point. A fuel car does everything that a car does and more, but less.

Assuming that there was a common, non-generic type T such that you could assign a fuel car and an electric car to T you could write:
Code: Select all
FuelCar f = new FuelCar();
ElectricCar e = new ElectricCar();
T car = NonDeterminableEvent() ? f : e;
car.Engine = ...;


I could do mess about with private setters, but I think that it has become obvious that this will just turn into a mess.

Thanks for your help.
ineon
 
Posts: 7
Joined: Tue Jan 31, 2012 11:23 am UTC


Return to Coding

Who is online

Users browsing this forum: No registered users and 6 guests