All 3 entries tagged OOP
No other Warwick Blogs use the tag OOP on entries | View entries tagged OOP at Technorati | There are no images tagged OOP on this blog
March 14, 2007
On the way home I thought of a way to override implementation class members in the user class.
class User use SomeImpl for IFooBar [OverrideImpl(IFooBar)] private SomeMethod() : void // specialized code... class SomeImpl : IFooBar public virtual SomeMethod() : void // Normal code
The macro can translate this into “real” code by creating a new class inside User that inherits from the implementation class. We override the virtual method and make call to the User method.
The partial expansion then looks like this:
class User use SomeImpl_User_Overrides for IFooBar private SomeMethod() : void // Specialized code class SomeImpl_User_Overrides : SomeImpl private _user : User public this(user : User) _user = user public override SomeMethod() _user.SomeMethod()
So then we use the specialized class as the implementation.
This approach will also work for abstract methods defined in the implementation class that require implementation.
I’ve been thinking more about traits and implementation classes in OOP.
I put together a quick program in Nemerle to demonstrate the ideas I’m playing with.
I defined a class that implements System.ComponentModel.IEditableObject. It takes a “user” object as a parameter and implements a simple stack based state saver. BeginEdit copies all the fields of the user, pushing them onto the stack. CancelEdit can then restore state by popping the stack and setting the fields back to those saved values. EndEdit simply pops the stack leaving the current values in place.
class EditableObject[T] : IEditableObject private _states : Stack[Dictionary[FieldInfo, object]] = Stack() private _user : T // We only take the reflection performance hit once per type T. private static _fields : array[FieldInfo] static this() _fields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) public this(user : T) _user = user public BeginEdit() : void _states.Push(CopyState()) public EndEdit() : void if (_states.Count > 0) _ = _states.Pop() // Discard top of stack else throw InvalidOperationException() public CancelEdit() : void if (_states.Count > 0) RestoreState(_states.Pop()) else throw InvalidOperationException() private CopyState() : Dictionary[FieldInfo, object] def dictionary = Dictionary() foreach (f in _fields) dictionary[f] = f.GetValue(_user) dictionary private RestoreState(previous : Dictionary[FieldInfo, object]) : void foreach (f in _fields) f.SetValue(_user, previous[f])
I now want to use this “implementation” class in many different classes. I do not want to inherit from this class directly. Trying to create an abstract base class purely to stuff lots of different implementation details together is just plain ugly too.
So I used the Nemerle ProxyPublicMembers macro.
class Person : IEditableObject [ProxyPublicMembers] _editable : EditableObject[Person] = EditableObject(this) [Accessor(flags=WantSetter)] mutable _firstName : string [Accessor(flags=WantSetter)] mutable _surname : string public this(firstName : string, surname : string) _firstName = firstName _surname = surname public override ToString() : string $"$FirstName $Surname"
With the single line:
[ProxyPublicMembers] _editable : EditableObject[Person] = EditableObject(this)
the three public methods BeginEdit, CancelEdit, EndEdit are inserted into Person and they simply call the respective methods on the _editable instance field.
A simple test of the code is:
static class Program static Main() : void def p1 = Person("Andrew", "Davey") Console.WriteLine(p1) p1.BeginEdit() p1.FirstName = "Foo" Console.WriteLine(p1) p1.CancelEdit() Console.WriteLine(p1) p1.BeginEdit() p1.Surname = "Smith" p1.EndEdit() Console.WriteLine(p1)
Andrew Davey Foo Davey Andrew Davey Andrew Smith
One of the advantages of this implementation class approach is the ability to store both instance and static state. The EditableObject only takes the reflection performance hit to get a type’s fields once. The user class never has to know about this state at all.
It would also be possible to enable a form of “overriding” by the user class. Perhaps it needs a special way to save and restore state. We just need a way to tell the implementation class to call the user to do something, rather than doing it itself. Delegates could be passed to the implementation class upon construction. Or perhaps a more declarative approach could be taken by marking “override” methods in a user class with an attribute.
[OverrideImplementation(EditableObject)] private CopyState() : Dictionary[FieldInfo, object] // do stuff here
We would just require some macro trickery to get this working I reckon.
As it stands the standard ProxyPublicMethods macro in Nemerle enables an excellent approach to modelling problems in clean OO style. I think an additional macro to tidy up the syntax would make things even nicer.
class Person uses EditableObject for IEditableObject
October 22, 2005
Writing about web page http://www.gotdotnet.com/Workspaces/Workspace.aspx?id=ccbb6b50-6c55-4291-b191-f5c5f80ba122
It took an afternoon of coding (and about a day or so of background thought process from the past month), but I finally created a working data-bindable aggregate object list view class. It grew out of the BindingListView
An example of where this is useful would be an RSS feed reader application. Here you would want to show a single feed's list of items and also allow the user to view all items from all feeds. The user should be able to sort the items and search, etc, even when viewing all items from all feeds. The AggregateBindingListView
The plain old BindingListView
One special point for people using the ABLV class, the "NewItemsList" property must be set before items can be added using UI controls like the DataGrid. That way the ABLV knows which list to add the new item to. Otherwise adding new items in that way is disabled. (BindingListView
I'm very happy with the code and have put together a simple RSS reader application to test it. More testing is required, since the concept of merging multiple lists and keeping things like additions, edits, deletes in sync is by no means straight forward. I also need to complete/update the XML documentation. A further addition to the library would be a class to parse SQL style filter predicates. (We already have a SQL sort property implemented.) This is a fair amount of work, but would allow things like:
view.ApplyFilter("Name LIKE 'A*' and Age >= 18")
Currently only coded filters (classes that implement IFilter) exist.
Any interested coders are welcome to join the GotDotNet workspace linked above.