Avoiding Typos via Output Methods

One of the issues with the code generation templates is that they do not test the syntax of the output as you type. I’m a VB coder, and that would be my fantasy, an editor that told me whether my templates produced valid output as I type. That’s nearly impossible to do, so don’t hold your breath.

In the meantime, you may have code like the following where

 

Private Function MemberGetPrimaryKey2() As String
      Return _
<code>
   Protected Overrides Function GetPrimaryKey() as <%= ObjectData.PrimaryKey.NetType %>
      Return m<%= ObjectData.PrimaryKeys(0).Name %>
   End Function
</code>.Value
End Function

 

Any typos between the <code> elements will result in dozens or hundreds of compiler errors when the output code is incorporated in your project. This is a pain in the neck to deal with, so anything we can do to have less typos is desirable.

When you create a UI for your users, you limit the number of mistakes the user can make via techniques like combo boxes. We can take advantage of Visual Studio’s editor to do a similar thing.

Your output code has logic within subroutines, functions and properties. While this code is trivial in the example above – just a return statement – your code will generally involve more complex logic. It’s important that you see this logic to evaluate it as you’re maintaining templates. The actual function declaration however, is not logic.

I created methods to output the enclosing declarations, as well as other non-logic based structures. This transforms the code above into:

 

Private Function MemberGetPrimaryKey() As String
      Return OutputFunction( _
                           “GetPrimaryKey”, _
                            Scope.Protected, _
                            MemberModifiers.Overrides, _
                            ObjectData.PrimaryKey.NetType, _
Function() _
<code>
   Return m<%= ObjectData.PrimaryKeys(0).Name %>
</code>.Value)
End Function

 

I’ve spread this out for clarity.

You can still typo the name of the method and the word Return. While you can make a bad selection, you cannot make a typo in anything else. And the parameters of the output function remind you of the types of modifiers that make sense. Under the covers, the OutputFunction creates a FunctionInfo object. While I’m not using it here, the OutputFunction method accepts a paramarray of ParmaeterInfo objects if you’re function needs parameters. Again, you can typo symbol names, but nothing else. Of course since the OutputFunction is within the code active in the IDE, you get full Intellisense, information blocks, background compilation and all the good stuff.

I’m using a lambda expression. In this case, it creates an in line delegate used to output the function body. If this template method becomes unduly complex, you could also use VB’s AddressOf operator to call a separate method as a delegate. In this case, the delegate signature I expect has no parameters and returns a string. Since the <code>…</code>.Value returns a string, it’s an effective delegate.

The FunctionInfo object includes an attribute collection. Thus, any attribute you desire to place on the function can be assigned by explicitly instantiating the function info object, rather than using the helper function.

This is quite similar to the OutputClass and OutputRegion methods I’ve showed earlier, but it takes the idea of using explicit method calls in the template to reduce the opportunity for typos in the output.

Output symbol typos are a problem, and you can avoid this through an enum or constants. You’ll use some of these constants across many templates and there will be a lot of them across your templates so I’d suggest you keep things clean by creating classes that contain your symbols. I created a namespace called “Symbols” and classes for Type, Method, Interface, etc. This gives nice clean Intellisense and makes it easier to find symbols in the constant list. Thus the code above becomes:

 

Private Function MemberGetPrimaryKey() As String
      Return OutputFunction( _
                           Symbols.Method.GetPrimaryKey, _
                            Scope.Protected, _
                            MemberModifiers.Overrides, _
                            ObjectData.PrimaryKey.NetType, _
Function() _
<code>
   Return m<%= ObjectData.PrimaryKeys(0).Name %>
</code>.Value)
End Function

 

That leaves “Return” as the only remaining opportunity for a typo – which is the subject of tomorrow’s post.

4 thoughts on “Avoiding Typos via Output Methods”

  1. Why use XML literals there? Doesn’t that complicate the issue compared to:

    Private Function MemberGetPrimaryKey() As String
    Return OutputFunction( _
    Symbols.Method.GetPrimaryKey, _
    Scope.Protected, _
    MemberModifiers.Overrides, _
    ObjectData.PrimaryKey.NetType, _
    m & ObjectData.PrimaryKeys(0).Name)

    End Function

  2. Bill,

    Thanks for coming by.

    In this particular case, you are correct. The full fuctional approach would be better. But how often does a function simply return a value rather than doing calculations? My simplification for the sake of example did obscure that here.

    I look forward to continuing this argument, but I can foreshadow that one of the reasons I’ve fallen very heavily to the code blocks is their use in a preprocessor. If I know precisely which code is output template code and which code is to run the template itself, I can accomplish things that are otherwise impossible.

    I know you’ve had a couple of concerns about my approach with the code blocks and I look forward to that discussion being public. But one of your concerns was performance of creating the code block for little purpose, such as in the code I posted. The performance of these templaets is blazingly, frighteningly fast. I look forward to some benchmarks later, but I believe they will probably prove to be faster at generation than any mainstream tools we have – anything short of just outputting a bunch of strings using string builder, and that I believe to be non-maintainable in large templtes.

  3. Hi Kathleen,

    The issue of performance really isn’t that important at design time unless it is really bad. My objections to using XML literals purely for line breaks was mroe to do with Beth’s samples of using them at runtime. There VB would be much better off if it had multiline verbatim strings.

    That leads me to the question why choose VB instead of C# as the primary language for the templates ?

    But my main question here was the OutoutFunction used above has 5 parameters on this overload, the fifth in your example takes a Func(Of String). Why not have that just as String ? Is the Func(Of STring) actually an Expression(Of Func(Of String)) and having the expression tree is of importance ?

  4. Bill,

    That’s a good point. Let me look into that. One of the reasons I want this out there is for more brains to help me make it better.

    At the moment, I can’t tell you why this needs to be a delegate. But I haven’t considered it veyr long. Earlier versions created arguments at a higher level (in output function) but I decided that was a bad design and removed the additional parameters.

    Thanks,

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>