in

CodeSmith Community

Your Code. Your Way. Faster!

Collection Templates 2.0 released

Last post 11-29-2004 11:39 PM by pneutam. 5 replies.
Page 1 of 1 (14 items)
Sort Posts: Previous Next
  • 07-12-2004 3:27 PM

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    Collection Templates 2.0 released

    Everyone,
     
    I've just uploaded version 2.0.0 of my Collection Templates on my website.
     
    I did not replace the copy in the usual thread with the latest release because version 2 drops the synchronized (thread-safe) wrappers, something I've long planned to do. The new templates are shorter, faster & easier to maintain... but obviously they're no longer fully compatible with the standard collections!
     
    For this reason, my website will also continue to host version 1.6.0, the last version to include sync wrappers. I won't work on this version anymore but it's a good start for anyone who wants to take over maintenance, as I think Eric would like to keep the sync wrappers in the version that comes with the CodeSmith distribution.
     
     
    Go here for details on the changes:
     
    • Post Points: 190
  • 07-12-2004 6:21 PM In reply to

    • ejsmith
    • Top 10 Contributor
    • Joined on 12-27-2002
    • Dallas, TX USA
    • Posts 2,185
    • Points 922,065

    RE: Collection Templates 2.0 released

    Chris,

    I'm OK with removing the sync wrappers. I know I voted for keeping them, but it's really not that big of a deal to use a seperate lock. I'm a fan of simplifying things as well so I will most likely update to this version in the 2.6 release.

    I am wondering if you could get rid of all the virtual methods then you would get another substantial perf improvement, correct? It looks like the only reason they are still there is for the read only wrapper. Maybe that could be a immutable flag when creating the collection?

    Also, I have some feedback for you. I'd like to see you move to a code-behind model rather than the include model you are currently using for your CommonScript.cs file. If you take these methods and create a real class that inherits from CodeSmith.Engine.CodeTemplate and then in your CodeTemplate directive in your templates set the Src= attribute to your .cs file and the Inherits= attribute to the name of the class in the CommonScript.cs file then I think that is a much cleaner solution than having a .cs file that can't be opened in VS.NET. Let me know what you think.

    Thanks,
    Eric J. Smith
    Eric J. Smith
    CodeSmith Tools, LLC
    Chief Software Architect
    • Post Points: 5
  • 07-12-2004 7:37 PM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    Eric,

    The read-only wrapper unfortunately has to remain a wrapper; that is, we must have a writable collection that accesses the same data. I haven't yet figured out how to do this without overrides, or how to do it efficiently at any rate. If I used a completely separate collection class I'd have to duplicate all the read access properties & methods which isn't very appealing.

    I'm afraid you're losing me with your next paragraph. You're talking about code-behind, and I don't even know what that means. Seriously. I think it's a web programming term, and I'm not familiar with that stuff. All I want is to instantiate templates from the command line, and without requiring the use of Visual Studio at all. The resulting .cs file should be static and completely self-contained.

    Honestly, CodeSmith is a great tool but I don't understand 90% of the discussions on these forums, or the VS integration features of CodeSmith itself for that matter. I really would appreciate if someone else could take the "official" maintenance of the collection templates off my hands, with code-behind and web programming and databases and all that new-fangled stuff. And I could just release my own Neanderthal command-line templates every once in a while. :)

    Cheers, Chris
    • Post Points: 5
  • 07-12-2004 9:38 PM In reply to

    • ejsmith
    • Top 10 Contributor
    • Joined on 12-27-2002
    • Dallas, TX USA
    • Posts 2,185
    • Points 922,065

    RE: Collection Templates 2.0 released

    Chris,

    Could you have a read only flag on some of the constructor overloads that take an initial set of data for the collection and then mark the collection as read only? Also, maybe you could have some static factory methods to create read only collections based on a given collection of the same type or a strongly typed array. I would think that you would want to do something like this to create your read only collection:

    SomeObjectCollection writableCollection = new SomeObjectCollection();
    writableCollection.Add(someObject1);
    writableCollection.Add(someObject2);
    SomeObjectCollection readOnlyCollection = new SomeObjectCollection(writableCollection, true);

    I would think you would just need to have a immutable read only flag in your collection that can be set during construction and then it can't be changed. I'm probably missing something though.

    As far as the second part of my post, there is no need to think about it as a web programming thing. Basically what you are doing is creating a template that inherits from your special class and therefore gets access to the extra methods it provides rather than simply including a class fragment into your template like you are currently doing. So your CommonScript.cs would become a fully fledged .NET class file and then you would setup your template to automatically compile that class along with your template and to also inherit from that class rather then inheriting from the default CodeSmith.Engine.CodeTemplate class. So basically you are introducing a layer of inheritance between your template and the base CodeSmith.Engine.CodeTemplate class and therefore getting access to all methods contained in that class. Here is what your CodeTemplate directive would look like:

    <%@ CodeTemplate Language="C#" TargetLanguage="C#" Src="CommonScript.cs" Inherits="CommonScript.SomeClassName" Description="Generates a strongly typed ArrayList collection." %>

    I don't think your collections are Neanderthal at all. I think they are quite awesome. I can understand if you don't want to maintain them anymore though. I can certainly take over their maintenance if you like, but I am hoping to not have 12 flavors of collection templates all over the place. I'd rather have one really good set of collection templates and when it makes sense to add something to them to make them better, then we can do that. It's up to you, if you would like me to take over their maintenance, I can certainly do so.

    Thanks,
    Eric J. Smith
    Eric J. Smith
    CodeSmith Tools, LLC
    Chief Software Architect
    • Post Points: 5
  • 07-14-2004 7:44 AM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    ejsmith said...
    Could you have a read only flag on some of the constructor overloads that take an initial set of data for the collection and then mark the collection as read only?
    Your're right, that would work. However, when I benchmarked a test implementation I found that ArrayList was no faster than with a derived wrapper; in fact, it appeared to be a bit slower. The if (IsReadOnly) checks apparently produce a worse performance than having an unsealed class and virtual methods.
     
    As for future maintenance, I'm afraid I have to ask you to take over. I just read through the current C# 2.0 specs to see if the new generics were lacking any features I needed, and I saw nothing of that sort. So while I'm still willing to fix bugs and answer questions, I don't really want to do any further CodeSmith-specific work, as I probably won't be using it anymore once Whidbey is stable enough.
     
    Cheers, Chris
    • Post Points: 5
  • 07-14-2004 12:25 PM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    PS: In view of the upcoming .NET generics, I would also advise you not to put too much work into the Collection Templates either. The new Framework will contain generic versions of all collections, and there's a separate work group called "Power Collections" whose goal is to devise new and better collection classes.

    I don't think it will make sense to use CodeSmith for a task that is more than adequately served by the Framework itself. As the other (much livelier!) forums indicate, CodeSmith is most popolar for its web and database programming capabilities. These areas are not likely to be handled adequately by .NET 2.0 so IMO it would make sense to focus and them, and drop the collections when generics become available.
    • Post Points: 5
  • 07-14-2004 6:02 PM In reply to

    • ejsmith
    • Top 10 Contributor
    • Joined on 12-27-2002
    • Dallas, TX USA
    • Posts 2,185
    • Points 922,065

    RE: Collection Templates 2.0 released

    Chris,

    I absolutely agree. Generics in .NET 2.0 are definately an awesome feature and I for one will be making MUCH use of them. Since .NET 2.0 is still probably a year away and then probably another year or so for everyone to migrate to it, I think there will be a need for these templates for a while still. But they're definately not something that I am planning to spend a lot of time on.

    Thanks,
    Eric J. Smith
    Eric J. Smith
    CodeSmith Tools, LLC
    Chief Software Architect
    • Post Points: 5
  • 11-23-2004 8:18 AM In reply to

    • pneutam
    • Top 150 Contributor
    • Joined on 07-30-2003
    • Posts 38
    • Points 735

    RE: Collection Templates 2.0 released

    Hi Chris,

    Have you ever thought of having the I<T>Enumerator interfaces inherit from System.Collections.IEnumerator, having Current : object and and <T> : <T> properties?
    Some thoughts:
    - Current<T> : <T> would do if having the type name as a property name is a pain.
    - IDictionaryEnumerator follows this approach, where it's Current property is inherited from IEnumerator and it has a separate Entry property.
    - Being able to cast to System.Collections.IEnumerator is a big plus.
    - I guess once you start down this path, you would have all the interfaces inherit from the System.Collections equivalents. Does this sound like a good idea?
    - You can more easily implement what I've had to do, but are yet to include them in any template. That is, a list that implements its item's parent class list interface.

    Cheers,
    Ben
    • Post Points: 5
  • 11-24-2004 2:21 PM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    Ben,

    As a matter of fact, all instances of any I<T>Enumerator interface already implement IEnumerator as well.

    That's because any return type for the I<T>Enumerator.Current property also satisfies the IEnumerator.Current property. If you look at the IEnumerable.GetEnumerator implementations for the various collections, you'll see that they simply cast the I<T>Enumerator instance to IEnumerator. So this is already possible.

    You could also implement I<T>Enumerator the way you describe, but then you wouldn't get automatic strong typing with drop-in compatibility.

    As far as I'm aware C# cannot "narrow" an interface definition, so there's no way to derive I<T>Enumerator from IEnumerator while maintaining the current instance compatibility.

    Does that answer your questions? I'm not sure what you were referring to in your last paragraph.

    Cheers, Chris
    • Post Points: 5
  • 11-25-2004 1:44 AM In reply to

    • pneutam
    • Top 150 Contributor
    • Joined on 07-30-2003
    • Posts 38
    • Points 735

    RE: Collection Templates 2.0 released

    As a matter of fact, all instances of any I<T>Enumerator interface already implement IEnumerator as well.
    Yes, your generated <T>List.Enumerator classes implement both I<T>Enumerator and IEnumerator, however this means you have to explicity cast to get an IEnumerator. I have functions that take an I<T>Enumerator as a parameter, and also other custom implementations of I<T>Enumerator. I've found it cleaner to have I<T>Enumerator inherit from IEnumerator directly, rather than having a convention that all such classes should realise I<T>Enumerator and IEnumerator together. Of course this does require you to use different property names for the strongly-typed parts of each interface, but I think that's okay. This is the approach MS took with IDictionaryEnumerator.
    The above applies to the I<T>Collection and I<T>List interfaces also.
    You could also implement I<T>Enumerator the way you describe, but then you wouldn't get automatic strong typing with drop-in compatibility.
    If you had I<T>Enumerator inherit from IEnumerator directly, your <T>List.Enumerator class would still have to have Current : Object. That doesn't void the drop-in requirement right? I am not sure what you mean by automatic strong typing. Is this an issue with the user having to know what the name of the strongly typed current property is?
    As far as I'm aware C# cannot "narrow" an interface definition, so there's no way to derive I<T>Enumerator from IEnumerator while maintaining the current instance compatibility.
    It's all got to do with the instance you have, and what interfaces it realises. If it realises it, you can cast it. In general, explicit casts are required unless you are going to a parent of the type of the variable you are casting.
    I'm not sure what you were referring to in your last paragraph.
    My last point was referring to the part lists plays in the managing of inhertance.
    Eg:
    1. I have a Cricketer class which inherits from a Player class.
    2. I build a strongly typed list of Cricketer instances.
    3. This list should be able to be operated on as if it was a strongly typed list of Player instances.
    Okay, so you want to tell a collection template that its item has a parent class and implement its interfaces accordingly. It's this general problem that lead me to use inheritance more in generating strongly typed collections.
     
    Cheers,
    Ben
    • Post Points: 5
  • 11-25-2004 8:17 AM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    Ben, the "drop-in" requirement is that you get strong typing without changing your code. You just write Current, swap your ArrayList for the template, and recompile. Now Current will produce the correct type automatically.

    This is very important for value types. When you do a foreach loop over a value type collection, the compiler auto-generates Current accesses which are then typecast to the desired element type if necessary. In your proposed implementation, Current would return an Object. That means the value type would be boxed, then unboxed again. That's extremely expensive if you don't do much else in the loop.
     
    In the released implementation, Current already returns the unboxed value type instance, straight from the backer array. So no boxing or unboxing occurs, and element access is much faster. There's no way around this issue, either, since the code generated for a foreach statement is built into the C# language.

    As for casting I<T>Enumerator instances to IEnumerator, I'm confused. Why would you ever want to do this? All cases that I can think of are covered by the IEnumerator.GetEnumerator method.

    As for collections that hold derived classes but should be interpreted as collections of base classes, I'm afraid I don't understand that either. When you have a Cricketer collection, you can use a Player reference to store Cricketer instances returned from collection members, as usual and without a type cast. Storing Player instances in this collection cannot be possible because Cricketer, being a derived class, may have extra data fields. You cannot auto-generate a derived type from a base type, you'd have to use specific conversion methods or the like.

    Post Edited (Chris Nahr) : 11/25/2004 8:20:45 AM GMT

    • Post Points: 5
  • 11-28-2004 11:38 PM In reply to

    • pneutam
    • Top 150 Contributor
    • Joined on 07-30-2003
    • Posts 38
    • Points 735

    RE: Collection Templates 2.0 released

    Chris,

    I see the requirement for "drop-in" functionality from a code management point of view.

    Re. the compiler. Are you saying that if you have a "public I<T>Enumerator GetEnumerator()" method and a "IEnumerator IEnumerable.GetEnumerator()" method, the C# compiler will use the former in a foreach statement? And again if you have a "public <T> Current" property and an "object IEnumerator.Current" property, it will use the former?

    If so, then there is a definite performance loss in having different property names. Does that not also suggest that enumerating over dictionary elements (DictionaryEntry structs) is sub-optimal in .Net?

    Casting I<T>Enumerator instances to IEnumerator is a general polymorphic requirement, ie I have functions that work on generic enumerators. This is for business objects, which are reference types (so therefore no boxing hit). I find enumerators useful when querying subsets of a large collections.

    Re. "list inheritance", it's only up-casting (casting to parent classes/interfaces) that I'm interested in. I'll extend the previous example to illustrate the need for this at the list level:
    - CricketTeam inherits from Team, and Cricketer inherits from Player
    - The Team class has a "IPlayerList Players" collection, and a number of related operations.
    - The CricketTeam class has a "ICricketerList Cricketers" collection, and a number of related operations.
    Now the CricketTeam.Cricketers association needs to override the Team.Players collection, and to do that the CricketTeam class needs to tell the Team class "this is my player list", and that player list needs to realise IPlayerList. Assuming we do wan't strong typing, this can either be done via a wrapper which up-casts on reading and down-casts on writing, or if the CricketerList implements IPlayerList itself. Thus far I have modified your templates to do the latter.

    Interesting discussion thus far!
    • Post Points: 5
  • 11-29-2004 8:43 AM In reply to

    • cnahr
    • Top 50 Contributor
    • Joined on 06-03-2003
    • Posts 105
    • Points 2,275

    RE: Collection Templates 2.0 released

    pneutam said...
    Re. the compiler. Are you saying that if you have a "public I<T>Enumerator GetEnumerator()" method and a "IEnumerator IEnumerable.GetEnumerator()" method, the C# compiler will use the former in a foreach statement? And again if you have a "public <T> Current" property and an "object IEnumerator.Current" property, it will use the former?
    Yes!  If there are public GetEnumerator and Current methods, the compiler will use them and ignore the explicit interface implementations.  Pretty cool, isn't it? smile
    pneutam said...
    Does that not also suggest that enumerating over dictionary elements (DictionaryEntry structs) is sub-optimal in .Net?
    If you explicitly iterate over DictionaryEntry structs then there will be a lot of type conversion.  But again, a foreach over a dictionary will automatically use the strongly-typed methods and get <K><V>Entry structs.
    pneutam said...
    Casting I<T>Enumerator instances to IEnumerator is a general polymorphic requirement, ie I have functions that work on generic enumerators. This is for business objects, which are reference types (so therefore no boxing hit). I find enumerators useful when querying subsets of a large collections.
    That's true, if you have a method that takes an IEnumerator parameter you'll have to cast your I<T>Enumerator instance explicitly.  I'm just surprised because I haven't really seen any C# code that passes IEnumerator instances around -- usually you want to get Count, at least, so you just pass the collection to an IList parameter or the like.
    pneutam said...
    Now the CricketTeam.Cricketers association needs to override the Team.Players collection, and to do that the CricketTeam class needs to tell the Team class "this is my player list", and that player list needs to realise IPlayerList.
    So you want the collection class itself to implement operations that are specific to the concrete type of its elements?  I can see how that would be useful but as I said before, I can't see how to do that in any general manner.  Having the CricketerList implement IPlayerList does seem the best choice to me.
     
    Cheers, Chris
    • Post Points: 5
  • 11-29-2004 11:39 PM In reply to

    • pneutam
    • Top 150 Contributor
    • Joined on 07-30-2003
    • Posts 38
    • Points 735

    RE: Collection Templates 2.0 released

    Chris Nair said...
    I'm just surprised because I haven't really seen any C# code that passes IEnumerator instances around -- usually you want to get Count, at least, so you just pass the collection to an IList parameter or the like.

    Well, you don't always want to lock a method to a specific collection type, I use BTrees for keeping business objects in memory as you can do range queries. An enumerator is a good mechanism for traversing a tree. They also fit in well when streaming is emphasised instead of passing around whole collections.

    Chris Nair said...
    So you want the collection class itself to implement operations that are specific to the concrete type of its elements?

    No. I generally avoid giving extra responsibilities to collections. The Player and Cricketer classes have their own responsibilities, as do Team and CricketTeam. The team classes also have responsibilities in relation to their players, e.g. Team.SortPlayers().

    Chris Nair said...
    Having the CricketerList implement IPlayerList does seem the best choice to me.

    Precisely! roll Team has a bunch of methods which operate on its Players collection, and CricketTeam has a bunch of operations on its Cricketers collection. What you want to enforce is, for example, a call to the SortPlayers() method on the CricketTeam instance actually sorts the Cricketers collection, and so on... This can be done if Team stores its collection as an IPlayerList, and CricketTeam overrides this collection with a CricketerList, which implements IPlayerList.

    What I've currently done is modified ArrayList.cst to be able to generate a parent element list interface.

    Having I<T>Enumerator inherit from IEnumerator is about cleaning up code that uses the collections, by not having to excplictly cast. It is not essential in solving the "association inheritance" problem discussed above. I see, however, that there is a trade off between ease of coding (implicit casting) and performance (strongly typed properties as chosen by foreach).

    I know your main goal with the collection templates is to avoid boxing at all costs. It's interesting that when implicit casting would become more useful (e.g. in a complex business model), value types aren't being used. The choice seems to be to either put up with explicit casting or have separate collection templates for value and reference types (not that I'm expecting you to do that of course).

    Let's think outside the box for a moment. Microsoft, please allow the specification of an attribute on enumerator class properties that tells the compiler that "this is a current property", and let the compiler choose the appropriate "current property" when compiling a foreach statement.

    Cheers,
    Ben

    • Post Points: 5
Page 1 of 1 (14 items)
Copyright © 2008 CodeSmith Tools, LLC
Powered by Community Server (Commercial Edition), by Telligent Systems