Dconstructor now has lifecycle support.
What does this mean? It means your objects will die a fiery death.
Previously, dconstructor supported two lifecycles: Instance and Singleton. Instance indicated that an object was entirely transient and had to be rebuilt each time it was required. Singleton indicated that an object was permanent and could be safely reused from the time it was first created onward to the end of time.
This has been generalized. Each object builder is now associated with a lifecycle. When it builds, it gets a lifecycle ID from the lifecycle. The next time it builds, it asks the lifecycle if its ID is still valid. If the ID is valid, then the builder returns the same instance; otherwise, it creates a new instance.
When registering a type, you can specify a lifecycle. You can also set a default lifecycle, and create LifecycleProviders to determine policy for particular types.
This is a part of dconstructor.build2, of course.
Tuesday, May 19, 2009
Dconstructor updates
Just a quick note about dconstructor: I've added dconstructor.build2, which is nearly a drop-in replacement for dconstructor.build. (Interceptors require modification.)
This reduces the executable bloat significantly -- in one mid-size example, dconstructor previously was responsible for a 75% increase in executable size (4.8MB to 8.3MB) and is now only responsible for about 100KB. The new version is less than 5% slower.
This also greatly decreases compilation times. examples/speed.d compiles in 3.4s rather than 14s.
The update is highly recommended, unless you need templated interceptors. Additionally, default_builder will soon be changed to use build2, since default_builder does not allow you to inject interceptors.
This reduces the executable bloat significantly -- in one mid-size example, dconstructor previously was responsible for a 75% increase in executable size (4.8MB to 8.3MB) and is now only responsible for about 100KB. The new version is less than 5% slower.
This also greatly decreases compilation times. examples/speed.d compiles in 3.4s rather than 14s.
The update is highly recommended, unless you need templated interceptors. Additionally, default_builder will soon be changed to use build2, since default_builder does not allow you to inject interceptors.
Thursday, May 14, 2009
The Visitor Pattern and Extensibility
I've been dealing with Dil lately. It's a compiler project for the D programming language, written in D. It makes use of the visitor pattern to provide semantic analysis. (The visitor pattern is a way of achieving dynamic dispatch via strongly typed overloads. It was a clever hack when it was first created.)
One issue with the visitor pattern is that it requires a lot of boilerplate code. If you want to have multiple semantic passes, you need to use an interface, and that interface requires a method for each type. If your visitor only cares about ten types and the interface supports fifty, you have a problem.
This doesn't much matter for dil -- very few types will not matter for any given visitor.
But let's look at a different problem. Let's say we want to log all visitor actions. Where do we do this? There are two choices: every single visitor method, or every single visited class. Similarly if we want to filter visited items, or set a breakpoint, or anything interesting like that.
I'm working on semantic analysis in Dil right now. For cleanness, I would like to split semantic analysis into possibly many phases. However, I would also like to combine semantic passes when possible for efficiency. To do this, I need to create a visitor that will coordinate between several visitors. This is an unreasonably large task with the current Visitor pattern implementation.
What else could I use, though?
In the past, I've used this concept:
This design is sufficiently minimal that it's easy to do a fair bit with it:
There is one problem with it, though: you have to do a lot of casting. In C#, you can use reflection to invoke the methods without caring about their types. In D, you can write a little wrapper:
A slightly simpler version is possible with D2's closures.
There is one problem with our solution: it uses associative arrays, which could be slow.
If you know what types you support in advance, you can map each to an index to get a very fast lookup. This requires a fast means of getting this index, however. I'm generally inclined to just use the associative array; it's going to be small in any case, so it will not incur a significant penalty in most cases.
One issue with the visitor pattern is that it requires a lot of boilerplate code. If you want to have multiple semantic passes, you need to use an interface, and that interface requires a method for each type. If your visitor only cares about ten types and the interface supports fifty, you have a problem.
This doesn't much matter for dil -- very few types will not matter for any given visitor.
But let's look at a different problem. Let's say we want to log all visitor actions. Where do we do this? There are two choices: every single visitor method, or every single visited class. Similarly if we want to filter visited items, or set a breakpoint, or anything interesting like that.
I'm working on semantic analysis in Dil right now. For cleanness, I would like to split semantic analysis into possibly many phases. However, I would also like to combine semantic passes when possible for efficiency. To do this, I need to create a visitor that will coordinate between several visitors. This is an unreasonably large task with the current Visitor pattern implementation.
What else could I use, though?
In the past, I've used this concept:
void delegate(Node)[ClassInfo] handlers;
void visit(Node node)
{
if (auto ptr = node.classinfo in handlers)
{
auto dg = *ptr;
dg(node);
}
}
This design is sufficiently minimal that it's easy to do a fair bit with it:
- Log each visited node
- Use multiple handlers per node type
- Use the same handler for multiple node types
- Filter or preprocess nodes based on some criterion available in the base class
- Ignore various node types by not writing any code for them
There is one problem with it, though: you have to do a lot of casting. In C#, you can use reflection to invoke the methods without caring about their types. In D, you can write a little wrapper:
class Invoker(T : Node)
{
void delegate(T) dg;
void invoke(Node node)
{
debug
{
// safety: cast and check
auto theNode = cast(T)node;
assert (theNode !is null, "expected: " ~ T.stringof ~
"but was " ~ node.classinfo.name);
}
else
{
// efficiency: force cast and assume
auto theNode = *cast(T*)&node;
}
return dg(theNode);
}
}
handlers[type] = &(new Invoker(dg)).invoke;
A slightly simpler version is possible with D2's closures.
There is one problem with our solution: it uses associative arrays, which could be slow.
If you know what types you support in advance, you can map each to an index to get a very fast lookup. This requires a fast means of getting this index, however. I'm generally inclined to just use the associative array; it's going to be small in any case, so it will not incur a significant penalty in most cases.
Wednesday, May 13, 2009
Metacity hacks
I've been using Enlightenment 17 as a window manager, but decided to go back to GNOME/Metacity since they're more polished. Overall a good move.
There are three issues I have with GNOME/Metacity. The first, and least solvable, is resources: GNOME is not lightweight. But I have sufficient RAM to ignore that issue for the most part.
The second problem is switching workspaces. In Enlightenment, going left from the leftmost workspace yields the rightmost workspace. Similarly for the rest of the directions. This is not the case for Metacity; you cannot go left from the leftmost workspace, or right from the rightmost.
Lastly, window placement. ANYTHING would be better than Metacity's policy, which is tiling all new windows from the top left. Open up four terminals on an empty workspace, you get what looks like one terminal with four titlebars, plus a lot of empty screen.
workspace_switch.py has sane workspace switching behavior. You can map Ctrl+Alt+Right and Ctr+Alt+Left to custom commands using gconf-editor (/apps/metacity/global_keybindings and /apps/metacity/keybinding_commands). Check workspace_switch.py --help for details.
I had to modify metacity to get reasonable behavior for its window locations -- metacity is renouned for its lack of configuration options.
In the metacity sources, go to src/core/place.c. Nuke all existing functions and add the following:
Perhaps I'll work on this -- certain things that would ideally be centered or center-parent are positioned randomly, such as the GNOME run dialog or modal dialogs. But for now, it's a huge improvement.
There are three issues I have with GNOME/Metacity. The first, and least solvable, is resources: GNOME is not lightweight. But I have sufficient RAM to ignore that issue for the most part.
The second problem is switching workspaces. In Enlightenment, going left from the leftmost workspace yields the rightmost workspace. Similarly for the rest of the directions. This is not the case for Metacity; you cannot go left from the leftmost workspace, or right from the rightmost.
Lastly, window placement. ANYTHING would be better than Metacity's policy, which is tiling all new windows from the top left. Open up four terminals on an empty workspace, you get what looks like one terminal with four titlebars, plus a lot of empty screen.
workspace_switch.py has sane workspace switching behavior. You can map Ctrl+Alt+Right and Ctr+Alt+Left to custom commands using gconf-editor (/apps/metacity/global_keybindings and /apps/metacity/keybinding_commands). Check workspace_switch.py --help for details.
I had to modify metacity to get reasonable behavior for its window locations -- metacity is renouned for its lack of configuration options.
In the metacity sources, go to src/core/place.c. Nuke all existing functions and add the following:
As you can see, this positions the new window at some random location, ensuring that no portion of the window is off the screen (unless perhaps the window is larger than the screen).
void
meta_window_place (MetaWindow *window,
MetaFrameGeometry *fgeom,
int x,
int y,
int *new_x,
int *new_y)
{
MetaRectangle work_area;
const MetaXineramaScreenInfo* xinerama =
meta_screen_get_current_xinerama (
window->screen);
meta_window_get_work_area_for_xinerama (window,
xinerama->number, &work_area);
int xrange = work_area.width - x;
int yrange = work_area.height - y;
*new_x = (rand() % xrange);
*new_y = (rand() % yrange);
}
Perhaps I'll work on this -- certain things that would ideally be centered or center-parent are positioned randomly, such as the GNOME run dialog or modal dialogs. But for now, it's a huge improvement.
Monday, March 17, 2008
Recursive it is.
Well, for the gtk# presenter injection issue, I determined that I could do the recursive method for in about fifteen lines of code, so I implemented that. I was stumped for quite some time because the recursion wasn't descending at all -- it turns out I was casting widgets to Gtk.Bin when I should have been casting to Gtk.Container.
The code:
The code:
public class ViewAttribute : Attribute {}
public class InjectAttribute : Attribute {}
[CastleComponent("bootstrapViews", typeof(BootstrapViews))]
public class BootstrapViews
{
private IWindsorContainer _container;
public BootstrapViews(IWindsorContainer container)
{
_container = container;
}
public void Bootstrap(Widget widget)
{
Container bin = widget as Container;
if (bin == null)
{
return;
}
foreach (Widget child in bin.Children)
{
Bootstrap(child);
}
object[] attrs = bin.GetType().GetCustomAttributes(typeof(ViewAttribute), false);
if (attrs.Length > 0)
{
foreach (FieldInfo field in bin.GetType().GetFields())
{
if (field.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0)
{
field.SetValue(bin, _container.Resolve(field.FieldType));
}
}
}
}
}
Sunday, March 16, 2008
gtksharp and MVP
Switching gears to C#, since, though I love D, I need a working mocks library to write any significant code in it, and dmd bugs prevent dmocks from working correctly.
I'm using gtk#/stetic to create a GUI of moderate complexity, and of course I'm using the Model-View-Presenter pattern. Reminiscent of ASP.NET MVP issues, the main problem is getting a reference to a presenter into a view -- gtk# doesn't use a central object builder that I can hook into; everything happens in a Build method.
So I have three options that I can pursue in achieving a reasonable MVP model:
Option #3, using generics, is reasonably simple, and it works unless I have one view with multiple presenters.
Option #2 is the fully general solution, which I probably won't be implementing. It'd be great, except for the speed, but it's rather yagni.
Of course, the problem with #2 is that my constructors will have to be modified, or the presenters might do something foolish:
As an aside, has anyone had luck getting CruiseControl.net running on debian?
I'm using gtk#/stetic to create a GUI of moderate complexity, and of course I'm using the Model-View-Presenter pattern. Reminiscent of ASP.NET MVP issues, the main problem is getting a reference to a presenter into a view -- gtk# doesn't use a central object builder that I can hook into; everything happens in a Build method.
So I have three options that I can pursue in achieving a reasonable MVP model:
- Each custom widget gets a reference to the Castle container and resolves its presenter that way.
- I build my GUI, then do a depth-first traversal of all the components, looking for an attribute set: [View(Type register)] on the class, [Inject] on the presenter(s). Any such classes, I register with the container, then fill in their dependencies. This works for everything that inherits from Gtk.Bin, but I have to copy it for any other gtk classes that my widgets derive from.
- Possibly using inheritance, my widgets subclass a SmartPart class and register themselves with a singleton (using the typical singleton pattern) that will register them with the container and fill in dependencies. This means I spend less time at runtime looking at widgets.
Option #3, using generics, is reasonably simple, and it works unless I have one view with multiple presenters.
Option #2 is the fully general solution, which I probably won't be implementing. It'd be great, except for the speed, but it's rather yagni.
Of course, the problem with #2 is that my constructors will have to be modified, or the presenters might do something foolish:
public MyWidget()
{
this.Build();
base(whatever);
}
// was:
// public MyWidget() : base(whatever)
// {
// this.Build();
// }
As an aside, has anyone had luck getting CruiseControl.net running on debian?
Wednesday, March 12, 2008
DUnit
I whipped together a quick unittest library, DUnit. Took less than an hour; apparently, SUnit took about two hours to write, so I'm in decent company.
This doesn't offer very much; in particular, there's no measure of progress. That's a deviation from the xUnit standard. And there's no way to control which tests get run. But I'm working on a better version already that offers those features.
On an unrelated note, dmd2 is too unstable to be usable, so dmocks is dead. I'll be updating it to dmd2.011, but probably no further, at least until dmd2 is in late beta or beyond.
This doesn't offer very much; in particular, there's no measure of progress. That's a deviation from the xUnit standard. And there's no way to control which tests get run. But I'm working on a better version already that offers those features.
On an unrelated note, dmd2 is too unstable to be usable, so dmocks is dead. I'll be updating it to dmd2.011, but probably no further, at least until dmd2 is in late beta or beyond.
Subscribe to:
Posts (Atom)