Using LINQ to write constraints in OCL style


I wanted to investigate using LINQ to write constraints “OCL-style”.   I made a “minimal language” and added a new NamedDomainClass called Property, embedded in ExampleElement.  Then I wrote the following validation method to check that all of the Properties attached to an ExampleElement are uniquely named:


[ValidationState(ValidationState.Enabled)]


public partial class ExampleElement


{


    [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]


    private void TestExampleElement(ValidationContext context)


    {


        var propnames = from p in this.Properties select p.Name;


        var distinctnames = propnames.Distinct<string>();


        if (propnames.Count<string>() != distinctnames.Count<string>())


        {


            context.LogError(“Non-unique property names”, “Error 1”);


        } 


    }


} 


 


A lot tighter than writing it in good old C#, I think.  Then I thought about “flattened sets”, i.e. navigating across more than one relationship and creating a single collection containing the results.  So I created SubProperty embedded in Property, and extended the constraint like this:


 


[ValidationState(ValidationState.Enabled)]


public partial class ExampleElement


{


    [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]


    private void TestExampleElement(ValidationContext context)


    {


        var propnames = from p in this.Properties select p.Name;


        var distinctnames = propnames.Distinct<string>();


        if (propnames.Count<string>() != distinctnames.Count<string>())


        {


            context.LogError(“Non-unique property names”, “Error 1”);


        }


 


        var subproperties = this.Properties.Aggregate(Enumerable.Empty<SubProperty>(),


                                                        (agg, p) => agg.Union<SubProperty>(p.SubProperties));


        var subpropnames = from p in subproperties select p.Name;


        var distinctsubpropnames = subpropnames.Distinct<string>();


 


        if (subpropnames.Count<string>() != distinctsubpropnames.Count<string>())


        {


            context.LogError(“Non-unique sub property names”, “Error 2”);


        }


    }


}


 


Not bad: but that line to calculate and flatten the subproperties is a bit complicated.  So, inspired by OCL, I defined a new extension method like this:


 


public static class C


{


    public static IEnumerable<U> Collect<T, U>(this IEnumerable<T> source, Func<T, IEnumerable<U>> func)


    {


        return source.Aggregate(Enumerable.Empty<U>(), (agg, p) => agg.Union<U>(func(p)));


    }


}


 


And now the subproperties line looks like this:


 


var subproperties = this.Properties.Collect(p => p.SubProperties);


 


I think I may be using that Collect method again!


 

Comments (7)

  1. Two questions:

    – Doesn’t LINQ’s SelectMany do what you want to do (flatten collections)?

    – Out of curiosity, why do you explicitly specify the type parameter to methods like Count (Count<string>() instead of just count())?

    Thanks!

  2. stevecook says:

    SelectMany – I will have to try that.

    The type parameters to Count and Distinct are unnecessary, as you point out.

    — Steve

  3. Oh one other style question (I’m very curious about how people view functional programming):

    You wrote:

    var propnames = from p in this.Properties select p.Name;

    Instead of:

    var propnames = this.Properties.Select(p => p.Name);

    Any particular reason?

  4. stevecook says:

    Really no reason at all.  I haven’t decided which I prefer yet.  I suppose to be consistent with OCL I would go for the second style.

    You are correct about SelectMany – it does just the same as my Collect.  So Collect is unnecessary.  I guess the name confused me. Still, writing the extension method was a good learning experience.

  5. Cool! I love seeing functional styles; _please_ keep blogging things like this. Hopefully, more people will see why this is vastly superior to writing it imperatively. In fact, do you have a snippet of what it would look like without the C# 3.0 features, for comparison?

  6. stevecook says:

    I guess doing it the “old way” would typically look like this:

    [ValidationMethod(ValidationCategories.Menu | ValidationCategories.Save)]

    private void TestExampleElementTheOldWay(ValidationContext context)

    {

       List<string> uniquePropertyNames = new List<string>();

       foreach (Property p in this.Properties)

       {

           if (uniquePropertyNames.Contains(p.Name))

           {

               context.LogError("Non-unique property names (old way)", "Error 3");

           }

           else

           {

               uniquePropertyNames.Add(p.Name);

           }

       }

       List<string> uniqueSubPropertyNames = new List<string>();

       foreach (Property p in this.Properties)

       {

           foreach (SubProperty sp in p.SubProperties)

           {

               if (uniqueSubPropertyNames.Contains(sp.Name))

               {

                   context.LogError("Non-unique sub property names (old way)", "Error 4");

               }

               else

               {

                   uniqueSubPropertyNames.Add(sp.Name);

               }

           }

       }

    }