Oct 23, 2007

Naming Conventions

I'm changing the project name. The name WindowMaker will be held by original project. It's possible that original development team will wake up at some day and produce something. I doubt that they will, but it's possible anyway. Since I'm practically forking original project, it's good idea to change the name. NextMaker seems like a good name for my project. I thought it out in times of first attempt to fork, and I think, I'll keep it now.

Now, to the style. I don't like pascalish names used everywhere in WindowMaker. I'll make them all lowercase and with underscore as word separator. The shorter name is better the longer one. Prefix change reflects change in project name. Now all function names will start with «nm» instead of «WM». Prefixes and suffixes of names will have some meanings: «nm_» stands for ordinary exported functions, «nmi_» is for internal functions, which is usually inlined, «nmt_» is for type-tags in object system and so on. For example WMReleaseObject function will become nm_release after change, and WMString will be nmt_string.

I won't do that all at once. Changes will be made only in parts of code I'm touching. There's also some plans on changing file layout and structure of API, but those are things I'll think about a little bit later.

Oct 16, 2007

WMArray vs. WMList

Yesterday I have analized sources of WINGs and WindowMaker a little. Now I'm certain that WMArrays are mostly misused. Little research showed that the most used pattern of accessing data in arrays is plain iteration form beginning to end. There are only four exceptions (out of approximately 23 use cases), where random access to data is used: WMList, WMPopupButton, WMSplitView, and switch panel. And I don't think that all of those can't be converted to using linked lists and be more efficient. Moreover, linked lists are actually used in many places in WINGs. For example, event handlers are organized in lists, notification observers are also organized in lists.

I'm not talking here about blind replacing of all arrays with linked lists, it would be stupid. But if I feel that linked list is more appropriate structure for particular task, I'll use it. If I see, that some linked list is implemented ad hoc, I'll replace it with WMLList data structure. There's possibility that after removal of WMPropLists, WMLLists will take place of proplist arrays.

Since the name WMList is already taken by list widget, I will use the name WMLList for data structure. I will probably change all names later anyway. Now I'm implementing WMLList object as double-linked list. If there will be never the need to iterate those lists in reverse direction, I'll remove second pointer, but currently I think this small memory overhead will pay off shortly.

Oct 12, 2007

Strings Handling

The idea is to keep length of string together with characters, just like in old WMData structure. In first attempt I allocated buffer with second call to malloc and stored only pointer to character buffer in the object. Then after playing a little with profiler I've changed code to use flexible array for a buffer. That also eliminated the need for WMString-specific destructor. Now I have a function WMCreateString which does basically the same as wstrdup (and a little more, because it at least keeps length of the string), but performs about 10% faster.

The other thing I will certainly need is some function to concatenate mupltiple strings. This function will replace wstrconcat, wstrappend, and also sprintf in many places. What I don't like about existing functions is calls to realloc. It is much better to collect strings to be concatenated in some kind of container like array or list, calculate length of the resulting string, call malloc and copy all data int new string. It would be also good in some situations to have function with variable argument list, that concatenates all its arguments.

I have even more ideas for handling strings. For example it may save a lot of CPU time if there will be string objects that doesn't copy literal strings when it's not absolutely needed, and keeps only pointer to it. Or it could be wise to create objects to represent substrings. They will keep reference to original string, offset, and length. Now I have ideas for at least four differend kind of strings. I think it is a good time to start experimenting with subobjects which will have more methods than just destroy.

Oct 9, 2007

Object System Issues

I have actually started hacking new object system for WINGs. The first thing I have noticed is that I don't want type tags to be dynamically allocated. It's very unclear when to destroy and free memory of such dynamic objects. Pointers to statically allocated objects should work as well.

It was excellent decision to start writing tests. The first thing I stepped on was dynamic type tags, and the second was lack of inheritance in C. WMRetainObject and WMReleaseObject functions now accept pointer to void type as argument as most generic type of pointers. There is no way to specify that function accepts pointers to objects only derived from WMObject structure. Now it is at least possible to use these functions without explicit type casts or some other ways to converting types.

I thought about where to start actually replacing current WINGs' objects with newer ones. It won't be PropLists. PropLists will be replaced almost at the end, just before I'll start hacking widgets. It won't be any of container types. All of them will be replaced little later. First two candidates for replacement is WMData and... strings. I choose to start with strings.

Oct 5, 2007

Testing

Nobody will argue that code needs testing. Testing can be performed in numerous ways. Sometimes testing is not enforced by project conventions (which happens at work mostly, because no-one is willing to spend time to create something that don't provide any cool features). In those projects I usually create bunch of files named a.c, b.c and so on in a root directory of a project. These are «tests». I compile and run them by hand. I never commit those files, and often forget what are they for. I'm always afraid to delete them by some mistake.

In my home projects I have a freedom to do whatever I want, including writing «useless» code solely for testing purposes. And I feel good. Whenever I want to know if my recent changes break something I can type «make sure» and check that everything is ok (or not ok :) ). I would like to do such things with WINGs too, but no-one before me cared to write any tests for WINGs. Few small programs in WINGs/Tests directory can't be counted as real tests. They're just like my ?.c files in projects at work with one small exception: they are commited in cvs.

I use cunit package to test the code written in C and valgrind to detect memory leaks. Usually, I just run cunit program under valgrind. I'm starting writing tests for parts of WINGs I touched. Tests won't be compiled by default. I don't want to force everybody to install cunit at their systems. To start testing go to WINGs/Tests directory and type «make sure».

Oct 2, 2007

Reference Counting and Objects

While I was looking at WINGs/memory.c eliminating malloc wrappers, I've found two functions that drew my attention. It was wretain and wrelease. If I'm not mistaken, the original idea was to eliminate all handcrafted reference counting code into one place. This is definitely the Good Thing™. But current implementation just sucks. Using hashtables for storing counters with pointers as a keys is definitely not my way of thinking. And those functions are used only in small number of objects in library, with handcrafted reference counting functions for all other objects.

Let's go into that problem little deeper. WINGs library does have objects. In fact there's at least three kind of objects, with different ways to distinguish types:
  • «raw» data structures like WMArray, WMBag etc with no way to determine type;
  • PropList-wrappers over raw structures with closed set of type tags;
  • widgets with open set of type tags, but with rudimentary support for creating new type tags.
Some of these objects use generalized reference counting and some not. That makes total of six potential object systems with five of them actually implemented. I don't understand why there should be more than one object representing one thing, moreover if those objects have different APIs. I don't understand why there should be more than one object system in single library.

I think I'll replace this object's zoo with something better. I came up with the following idea. Two common fields for all object are almost obvious. These are some kind of a type tag, and a reference counter for that object. The best kind of type tag I can think of is a pointer to a structure with pointers to methods as fields. I'll start it with the single destroy field, which if present will handle additional operations needed to destroy an object. This solution may add just a little overhead to some «raw» objects, and no overhead to all others. They're already have something like counter field, type tags or destructor field. This overhead should pay off when I start replacement of PropLists with new objects.