GOTO OATC Wiki Home

One of the proposed things to do in our iterative development of OpenMI version 2 is to use some types of collections in the standard interfaces. One example is the ILinkableComponent interface where we have the method GetIntputExchangeItem(int index) and the property IntputExchangeItemCount. To make this feel like more object oriented the count-thing and the Get-thing should be bundled into one object (or one property of the interface). The simplest way to do this is to use e.g. the .Net type List, and with .Net version 2 such lists can be made type safe. This means that such list is in the standard defined to contain only objects of specific types (as for the GetInputExchangeItem example such list would be allowed to contain only objects of type IInputExchangeItem. However, there is another problem. If the normal type of list is used, methods such as myList.Add(object) will also be available, which we do not want for the standard.

In the two code boxes below two different possible solutions to handling lists in the standard is shown. In the first example a .Net list type called ReadOnlyCollection is used, and in the second example a new list interface is defined.

The first example has the advantage that the InputExchangeItems property will have a number of methods inherited from the .Net list. This means that e.g. constructions such as foreach can be used. The disadvantage is that it reduces the freedom for alternative implementations, only the ReadOnlyList can be used.

In the second example there is more freedom for implementation. The IIlist contains only one property and one method. The disadvantage is that constructions such as foreach cannot be used.

After playing around with these different solutions I have doubts whether it is such a good idea to change the version 1 architecture with respect the lists after all. Seems like we gain very little. We will get rid of the count properties but no real extra functionality is added and we sacrifice some freedom with respect to implementation. If we want to used list types in the standard we should used it everywhere, which also means for elementSets. Especially for elementsets it becomes clear that freedom for implementation is lost. An elementSet should be a list of elements, which will force us to define a IElement interface. In version one a IElement interface is not needed, which actually is pretty smart when implementing IElementSet for e.g. a regular 2d grid. I this case a class of type IElement never needs to be created.

Using ReadOnlyCollection
public interface ILinkableComponent
    {
        ReadOnlyCollection<IInputExchangeItem> InputExchangeItems { get; }

    }

public class LCTest : ILinkableComponent
    {
        private List<IInputExchangeItem> _inputExchangeItems = new List<IInputExchangeItem>();

        public System.Collections.ObjectModel.ReadOnlyCollection<OpenMI.Standard.IInputExchangeItem> InputExchangeItems
        {
            get { return _inputExchangeItems.AsReadOnly(); }
        }
    }

class TheMainPrograme
    {
        public void test()
        {
            LCTest myModel = new LCTest();
           
            string description  = myModel.InputExchangeItems[0].Quantity.Description;
            int numberOfInputExchangeItems = myModel.InputExchangeItems.Count;

        }

    }

Using tailored list
public interface IItems<T>
    {
        T GetItem(int index);
        int Count { get; }

    }

public interface ILinkableComponent
    {
          IItems<IInputExchangeItem> InputExchangeItems { get;}
    }

public class Items<T> : IItems<T>
    {
        private List<T> list = new List<T>();

        #region IItems<T> Members
        public T GetItem(int index)
        {
            return list[index];
        }

        public int Count
        {
            get { return list.Count; }
        }

        #endregion

        public List<T> List
        {
            get { return list; }
        }
	
    }

public class LCTest : ILinkableComponent
    {
        
        private Items<IInputExchangeItem> inputExchangeItems = new Items<IInputExchangeItem>();

        public IItems<IInputExchangeItem> InputExchangeItems
        {
            get { return ((IItems<IInputExchangeItem>) inputExchangeItems); }
        }
    
    }

class TheMainPrograme
    {
        public void test()
        {
            LCTest myModel = new LCTest();
            myModel.MyInit();

            
            description = myModel.InputExchangeItems.GetItem(0).ElementSet.Description;

            ((Items<IInputExchangeItem>)(myModel.InputExchangeItems)).List.Add(new Oatc.OpenMI.Sdk.Backbone.InputExchangeItem());
 

        }

    }




  • No labels

3 Comments

  1. Unknown User (don)

    After looking on current Backbone implementation we can see that collections are used internally, not generics-based because they were not available when OpenMI development was started:

    	public abstract class LinkableComponent:MarshalByRefObject,ILinkableComponent 
    	{
    		private ArrayList _inputExchangeItems  = new ArrayList();
    		private ArrayList _outputExchangeItems = new ArrayList();
                    ...
    

    I fully agree with you that there is no need to make access to exchange items of components in a read-writable way, especially no need to require it in a standard. IMHO optimal solution seems to be a property returning simple read-only array:

    interface ILinkableComponent
    {
       IExchangeItem[] InputItems { get; }
       IExchangeItem[] OutputItems { get; }
    
       ...
    }
    
    public class SimpleComponent : ILinkableComponent
    {
       IExchangeItem[] input;
       IExchangeItem[] output;
    
       public IExchangeItem[] InputItems 
       { 
          get { return input; }
       }
    
       public IExchangeItem[] OutputItems
       { 
          get { return output; }
       }
    
       ...
    
       public void Initialize(IArgument[] arguments)
       {
          ...
    
          input = new IExchangeItem[inputSize];
          output = new IExchangeItem[outputSize];
       }
       ...
    }
    
    // usage
    void Test()
    {
       SimpleComponent c = new SimpleComponent();
    
       int inputItemsCount = c.InputItems.Length;
    
       foreach(IExchangeItem exchangeItem in c.InputItems)
       {
          ...
       }
    
       int outputItemsCount = c.OutputItems.Length;
    
       foreach(IExchangeItem exchangeItem in c.OutputItems)
       {
          ...
       }
    }
    
    
    • read-only
    • lenght is embedded
    • foreach can be used
    • simple access by index can be used
    1. Seems like a very fine solution. I wonder why we did not think of this when we made version 1 (always get a bit suspicious when things look too easy). The clear advantage is that it does the job without any fancy stuff. Please everyone also take a look at Gena's idea.

  2. Genna's solution looks good as long is Java compatible. Otherwise a ICollection interface definition in OpenMI namespace might suffice. I dont think we want anything in the standard that is obviously language lead. We use interfaces, so thats fine, but we should use interfaces further rather than add additional concepts. it would be trivial for a specific language to implement OpenMI.Collection in terms of specific language constructs.