Friday, August 20, 2010

Every day Jackson usage, part 1: Immutable objects

Here's something that has been requested by multiple readers: an article detailing how to use Jackson to support specific usage patterns. "Jackson usage patterns" if you will.
And first topic I want to cover is.... Immutable Objects.

1. Immutable Objects: what, why?

Immutable objects in Java are objects that are either stateless (behaviour-only) or where state is set at construction and can not be changed.
For example, here is a simple immutable object class:

 public class Point {
  private final int x, y;

  public Point(int x, int y) {
   this.x = x;
   this.y = y;
  }
 
  public int getX() { return x; }
  public int getY() { return y;
 }

The main difference to more common approach is that there are no setters; instead, values of x and y are assigned just once in constructor. That is actually a big difference, and makes this a better approach for many use cases.

But why is it better? One side benefit is just simplicity; fewer methods to write (and maintain), less code, is generally better. But the main benefit is that immutable objects are thread-safe requiring no synchronization: instances can be freely shared and reused between different threads. Immutable objects are also usable as Map keys (in fact Map keys are required to be immutable; or at least never modified while used as a key). This allows very efficient reuse using fly-weight pattern and canonical objects. In fact, unless mutability is specifically needed I try to keep objects immutable, as sort of baseline.

There are also challenges: inability to change state complicates many things. But it is worth noting that immutability only affects instance; and system-level changing of things is quite easy. A common pattern is that of defining factory methods like:

 public class Point {
  // ...
  public Point move(int byX, int byY) { 
    return new Point(x+byX, y+byY);
  }
 }

so that instances are never modified; instead, new instances are constructed based on previous state and delta of some sort. This works nicely for many cases, and is also basis for many lock-free data structures.

But enough about object immutability itself. What is more interesting is if and how one can support such use cases with Jackson.

2. Can Jackson do it?

Initially it might seem unlikely that Jackson can work with immutable objects: after all, aren't Beans required to have getters and setters? "Classic" Java Beans do indeed need setters (mutators). And as a consequence many data binding frameworks (JAXB) require setters, or access to public fields.

But Jackson is neither limited to Beans -- it can work with many other kinds of POJOs -- nor does it require setters for injecting data in. And unlike many serialization frameworks, Jackson does not require access to object fields either (although it can certainly use them when instructed).

As with most Jackson functionality, there are multiple ways to achieve immutability. Let's have a look at them one by one.

3. Simple Immutable Objects using Creator methods

The simplest way to make Jackson produce immutable objects is to instruct it to do what Point class was already doing: make Jackson use constructor to feed in data. This is similar to how Dependency Injection frameworks (like Guice do), and requires use of simple annotations (mix-in annotations work fine):

 public class Point {
  private final int x, y;

  @JsonCreator
  public Point(@JsonProperty("x") int x, @JsonProperty("y") int y) {
   this.x = x;
   this.y = y;
  }
 }

and with this, Jackson will use constructor for passing logical properties "x" and "y", instead of trying to use fields or set methods. The only difference to "regular" properties is that @JsonProperty is not optional for constructor arguments, because bytecode does not store names of parameters and they must be explicitly specified. As with other properties one can configure different aspects, including custom deserializer to use if any, specific subtype to use and so on.

Alternatively one can also define factory methods (constructors and factory methods are collectively referred to as "Creator methods" in Jackson documentation), like so:

  public class Point {
   @JsonFactory
   public static Point makeAPoint(@JsonProperty("x") int x, @JsonProperty("y") int y) {
    return new Point(x, y);
   }
  }

Simple? Note too that you can use Creator methods with other kinds of POJOs. You can also mix and match field access and setter access; if so, Creators are always called first to instantiate an Object, and setters and fields are used afterwards. So you don't have to go all immutable; it is often beneficial to just make certain fields immutable.

4. Faking Immutability

One thing that I did not yet mention is that there is difference between complete immutability (as shown above), and just perceived immutability. By latter I mean that there is no way to change state of the object form outside (except via Reflection, more on this in a minute) -- if you can not change the state, it is as good as immutable. Consider example where fields "x" and "y" were not marked as final: fields are still private, and therefore inaccessible from outside. But they can still be modified via reflection. Since we are not considering security implications here, such bean would be about as good (with respect to benefits of immutability) as one were fields were forced final.

With Jackson you could actually use such fields as well; by having Point class like this:

 public class Point {
  @JsonProperty private int x;
  private int y;

  public Point() { }

  @JsonProperty private void setY(int y) { this.y = y; }

  public int getX() { return x; }
  public int getY() { return y; }
 }

So during deserialization, Jackson would directly access field "x" (using Reflection) and call method "setY" to set value of "y". But since regular code can not modify things further, object would work just as truly immutable one does. This can lead to even simpler code if you just annotate private fields so there is no need to copy values in constructor.

5. Immutabilty by interface / implementation separation

Yet another possibility to achieve perceived immutability is to separate interface of an object into multiple pieces: public read-only (immutable) part that is exposed to application, and mutable part that is used for actual data binding. In our case we could have basic Point interface, implemented by PointImpl class; latter with necessary fields and possibly setters; and interface just having accessors (getters). So as long as application code only deals with interfaces we achieve immutability from design perspective.

But the problem here is that of dependencies; consider a POJO like:

 public class Circle {
  public Point center;
  public int radius;
 }

how would Jackson know that 'center' instance really needs to be of type PointImpl, as Point is just an interface (and can not be created)? Simplest way is to use annotation @JsonDeserialize, which can define actual (sub)type to use (as well as custom deserializer to use; or for Collection and Map types, actual types of values and map keys, and custom deserializers for them too!):

 public class Circle {
  @JsonDeserialize(as=PointImpl.class)
  public Point center;

public int radius; }

and things would work as expected (alternative would be custom deserializer which is bit more work) -- 'center' would always be an instance of PointImpl.

6. Even crazier stuff: Materialize it!

Ok: when I said that one can not just create an instance of an interface, I omitted something cool that Jackson 1.6 will bring: ability to "materialize interfaces". So even though 1.6 has not yet been released (it will be shortly, by end of August!), let's have a sneak peek at this cool feature.

Actually, there is really very little to say, except that instead of having to define PointImpl, one could just register bean materializer (see this piece of documentation for details):

  mapper.getDeserializationConfig().setAbstractTypeResolver(new 
  AbstractTypeMaterializer());

and then Jackson would create an implementation class for any non-concrete Bean (abstract class or interface where all abstract methods are getters or setters) type and use it for deserialization. Pretty cool eh?

This is actually also another fakin' it method: materialized class actually has appropriate access (setters by default), but those are only visible to Jackson itself (or other code that uses Introspection to find methods).

7. More?

These are ways I can think of to make Jackson construct immutable objects. If you can think of others, let me know. :-)

But beyond this, I have some ideas of topics to write about, like

  • How to filter out stuff to serialize (JSON Views, @JsonIgnore)
  • Working with Polymorphic types (@JsonSerialize(as=...), @JsonTypeInfo, default typing, ...)
  • Working with Open Content (models)

And if/when you can think of other Jackson Usage Patterns, please let me know! I'm sure there are more than 3 areas of usage that could use some more documentation.

Saturday, August 14, 2010

Another interesting(-looking) data store on Java platform: Krati?

Ok, looks like there is one more storage option I really should investigate, Krati. What seems appealing (at first glance) is the understanding that performance optimization on Java platform are quite distinct from those for systems written in C/C++ (or on Erlang and other distinct platforms). And especially trying to make good use of big discrepancy between performance of random access versus sequential access; given that latter can be an order of magnitude faster, it may well make sense to add more processing to be able to sequential writes even if higher-level abstraction was concurrent random-access.

Of course there are lots and lots of other choices: from stripped-down "traditional" storage (like using MySQL InnoDB, see for example g414-inno) to BDB variants, Tokyo Cabinet and Redis. And higher-level systems that use roll-your-own storage (like Cassandra does by default). And this is good, I think; for truly optimal performance one-solution-cant-fit-all -- different storage options are best fits for different system designs.

Tuesday, July 27, 2010

Fun with bytecode generation, minus problems with generic signatures

One thing that has been on my TODO list for multiple years moved up to my "current tasks" list: that of using Java bytecode generation for something useful: for "materializing interfaces" (typically simple Bean interfaces), that is, constructing concrete implementations of interfaces that only consist of simple getter and/or setter methods. It will be one of major new features for Jackson 1.6, codename "Mr Bean". In fact there is just one other such mental todo task from that era (which would be "use Groovy for something useful")...

Implementation was started by my colleague Sunny G at Ning (which is big reason why it got started at all!) and uses minimalistic, lean and mean ASM bytecode generation package for actual low-level work. This is good in keeping dependencies to minimal (in fact, Jackson mrbean module will embed repackage version of ASM 3.3), and will probably also result in simple bytecode. But the downside is that code to write is quite low-level.

Working with low-level code generation actually brings back memories from last millennium -- I wrote 68000 assembly in early 90s, and 6502 machine code before that in late 80s. Name ASM is actually quite apt for the package as using ASM is quote similar to using full-feature Assembler package, which is still a notch above bare machine code or using machine code monitor (for those who remember what that meant on, say, Commodore-64). This is to say, it's actually bit of fun for me; although amount of time spent on actual debugging and troubleshooting is considerably higher than with "normal" Java coding. But at least you don't have to manually calculate various offsets (local variable and stack sizes for example), or allocate constant Strings in per-class constant tables. Writing actual code is still rather involved however.

At this point basic functionality works acceptably, leading to the first snapshot release of Jackson-1.6.0. But there is one serious problem that I have been unable to resolve. Although ASM actually does provide some support for dealing with generics -- that is, ability to declare generic signatures of fields, methods, and supertypes -- and although I am using functionality exactly as it should be (including verifying exact form signatures need, compared to type-erased 'description' parameters), end result is only half-working. Half meaning that if disassembling resulting class bytecode using ASM itself, generic signatures are found; but when using JDK reflection (java.lang.reflect.Method/Field, getGenericType()), only type-erased information is found. I still hope to resolve this; I hope someone on ASM users list can point out what I am doing wrong. There shouldn't be anything fundamentally hard about making it work.

Anyhow, I thought this might be somewhat interesting; I'll get back to working on finalizing 1.6.0 so it gets released before summer ends and it is time to (yet again!) contemplate brewing of dreaded Blackberry Beer! :-)

Saturday, July 10, 2010

Every day JSON work: comparing JSON documents for equality ("are these JSONS same?")

One JSON task that may seem trivial but is not is that of checking whether two given JSON documents are equal: that is, have same structure and values, and ordering of array values is same. It is not sufficient to use String equality comparison because while equality of Strings does mean contained JSON is equal, differing Strings does not mean they are not equal, since:

  • It is possible to quote characters differently using \uXXXX mechanism
  • Order of properties of JSON objects is undefined (at conceptual level); meaning that physical ordering may differ while conceptually JSON is still identical

So how should one compare equality? With Jackson, simplest way is to construct JSON tree (JsonNode) for documents to compare and just use JsonNode.equals()! Like so:

  ObjectMapper mapper = new ObjectMapper();
  JsonNode tree1 = mapper.readTree(input1);
  JsonNode tree2 = mapper.readTree(input2);
  boolean areEqual = tree1.equals(tree2);

I realized that this (fact that JsonNode.equals() works "as expected", doing deep value comparison) is not documented outside of Javadocs (it will be now, I will add something at FasterXML Jackson Wiki). But hopefully it was already known by experienced Jackson users. Either way, here's how JSON content comparison can be done easily and reliably.

Monday, June 28, 2010

Async HTTP Client 1.0 released

Ok, this announcement went out last week, but it is important to re-iterate: version 1.0 of Ning async HTTP Client is now out!

This is good news for multiple reasons: obviously ability to do asynchronous (read: non-blocking, i.e. no need to use one thread for each and every open connection) HTTP communication is valuable in itself. But I also hope that this spurs some friendly competition in improving all HTTP-based communication on Java platform -- there are still features that are not implemented, and due to complexity of efficient connection handling, there should be still room for improvement with performance as well. And finally this should lead to wider adoption of this relatively new library, so that it gets properly battle-tested and proven.

I am actually planning on using this client for cases where regular blocking client could work, to see how well it performs and exactly how easy it is to use non-blocking API, compared to existing blocking alternatives.

Tuesday, June 08, 2010

Introducing My Newest Open Source project: Tr13 (that is so 1337!)

I have briefly mentioned that I have been working on a new little low-level data structure package, called (Ning) Tr13, started at GitHub. Now that code is getting ready and tested, it is time to "formally" introduce it.

Tr13 is an interesting project form multiple angles: for one, it is my first "corporate-sponsored" Open Source project (i.e. related to may day-to-day work -- although not focus of it, just a useful thing for me and hopefully my colleagues at Ning). This alone is worth celebrating; the whole process has been remarkably smooth from 15-minute end-to-end approval process (take note Amazon developer community...), tosteady if somewhat slow development itself (there is nothing groundbreaking from CS perspective -- more on this below).
This is also a rare case of my already having reasonably clear idea as to where I would be using this package. It may sound surprising, but truthfully most open source libraries I have written, I have not actually absolutely needed them before writing. :-)
(there are exceptions: Java UUID Generator is something I wrote since I needed it -- but not so for Woodstox, or even Jackson, to some degree, both of which I have extensively used after I wrote them).
And finally, well, it is a change from my more common data format parsing / data binding work. Although I was thinking of "climbing up the stack" to write something higher level, I ended up going the other way, a slight detour.

Anyway, I digress. So...

What exactly is tr13?

It is a space-efficient ("compact") read-only implementation of Trie data structure, with slight modification to use Patricia/Radix structure for leaves (but not for branches, since that did not seem useful for my use cases).

Current implementation supports two kinds of Tries:

  1. Byte[] key, variable integer (~= long) value
  2. Byte[] key, byte[] value

In both cases, byte[] is typically a String, but can be any other serializable thing; for example, ints and longs could be trivially converted to 4/8 byte keys. Separate variant for variable-length integers is further optimization for my initial use case, where values are generally small ints, which can fit in a single byte, but where it is convenient not to be bound by arbitrary limits (like 256).

Internally structure is actually just a regular byte array (or, alternatively, ByteBuffer, to allow for "GC-free" tries!). Data format needs to be documented, but is a rather simple implementation of basic trie ideas, nothing to write a dissertation about.

Why does it Rock?!

Given how good plain old JDK HashMap can be -- you could just use HashMap<String,Integer> for the first case -- what is so special about tr13?

Simply put: memory usage, or lack thereof (ditto for GC activity). This because:

  1. Overall memory usage is pretty tight -- for test data I have (30 million entries of typically 13-byte key, small integer number == 600 meg input file), trie structure actually uses less memory than its file representation (by about 35% less). And,
  2. Since it is all in just TWO objects (raw byte array, wrapper Trie object), it should keep GC rather happy.

This is not coincidental, since the use case we have is that of sizable routing tabls that should ideally be kept fully in-memory. Hence compactness of data structure, with reasonable lookup times (i.e. no linear search), was design criteria. Even other somewhat frugal data structures (like b-trees) are not anywhere as space efficient.

Downsides?

First obvious limitation is that it is a read-only data structure: you must have all the data at hand when building it. Data also has to be ordered, not necessarily alphabetically (although that is the usual way), but in a stable lexicographic ordering, such that build process has invariants it needs. This is not as big a limitation as it might seem, at least when merging functionality (more on this later on) is added. For now it may be necessary to re-build data structure regularly, and keep an additional "short-term" lookup data structure at hand for additions that are needed between re-builds.

As to performancem resulting data structure is not the fastest way to find things: from complexity standpoint it is a linear algorithm, compared to theoretically constant time for hash-based alternatives. This may or may not matter; it should not matter a lot with respect to key length (HashMap has to calculate hash for key and compare key bytes, unless keys can be canonicalized). Another potential performance concern is that trie data structure does not have much locality; but this too is unlikely to be much worse than for typical alternatives. In fact, due to high memory efficiency, and use of plain byte array, it is not guaranteed that HashMap has any better locality, even if a single lookup results in a match (this due Java GC's habit of "shuffling" object data around).

All in all, Tr13 does much more work when finding values, since it traverses data structure once per each key byte (except for Patricia-optimized tail, which may be multi-byte linear match). So I would not expect it to be as fast as direct hash lookups.

But in the end, these are speculations, and the real test would be use.

... or, how about a performance test?

Performance Testing

Ok: the question of efficiency is something worth looking deeper into. And so I wrote a benchmark that compares VIntTrieLookup (byte[]-to-vint trie) against HashMap<String,Integer> (for curious, it's under 'src/java/test/manual/' in source tree). Test loads all the entries in memory, and then performs randomized lookups (one lookup for every key, but order shuffled so as to be different from 'natural' ordering of trie).

When given a subset of the whole data file (turns out HashMap hogs so much memory that I just can't test the whole data set!) -- a 32 meg, 2 million entry chunk -- here are the results:

Memory usage:

  1. Tr13: 20.6 megs (reduction of about one third)
  2. HashMap<String,Integer>: 314 megs

So in this case, HashMap<String,Integer> uses about 15 times more memory than Tr13 (note: Integer values are canonicalized using Integer.valueOf -- without this, usage would be 360 megs).

And what about performance? What is the cost of compactness?

For 3 million lookups, time taken was:

  1. Tr13: about 5000 milliseconds (about 400,000 lookups per second)
  2. HashMap<String,Integer>: about 1200 milliseconds (about 1,670,000 lookups per second)

so HashMap is about 4 times faster than Tr13 for lookups, on my system (2.33 ghz mini-mac, JDK 1.6), for given data set.

Since my first need is to be able to do lookups in memory, performance difference is not of particular importance (there might be one or two lookups per request, so anything in tens of thousands per second would work), but it is good to know rough order of magnitude difference.

What next?

At this point Tr13 should be ready for use, and I plan to release version 0.5 soon. The only thing I am waiting for is to get a Maven repository set up at Sonatype OSS repository (kudos to Sonatype for this free hosting!), so that Maven-based (and I assume, Ivy-based) projects can use it. This is actually what I need for my daytime use.

But beyond Maven deployment, there are some additional features I want to implement in near future, such as:

  • Ability to traverse through entries (Map.Entry<> style)
  • Ability to merge two tries efficiently -- could be built quite easily given iterator functionality
  • ... document the data structure (ok ok, not a development task, but "hard" (read: tedious) yet necessary work) -- it is very simple, but not so simple that reading code would make it obvious.
  • Current implementations are limited to 2 gigs, due to Java byte[] and ByteBuffer limitations. But fundamentally there is nothing particularly hard about writing segmented versions where only segments would have this limitation (well, probably values too, but I don't see any need for 2gb+ values in my tries...)

Merging functionality specifically would be useful for "semi-mutable" lookup data structures. For data that evolves slowly (which is the case for routing table use case I have), it is possible to keep track of needed modifications (in a, say, HashMap), and do primary lookup against that data structure, and only if no match is found, against immutable trie. And when this short-term data structure goes enough, or enough time passes, trie could be re-built with existing and new data. Repeat and rinse.

And perhaps it might even be possible to work some more on fundamental data structure itself, and find ways to make it mutable. Insertions (and deletion) operations would be rather costly, due to global changes needed (another downside of compactness is that changes tend to spill far). But even slow mutability would be better than no mutability; and perhaps there could be ways to trade some space (intentional unused regions within trie, to be used for insertions?) for lesser likelihood of having move all the data around.

Wednesday, May 19, 2010

Un-hibernating projects: Java Uuid Generator, getting ready for 3.0!

As cycle of seasons has rolled to late spring, it is time for hibernating things -- bears, and stagnant open source projects -- to wake up and start moving. It just so happens that this is the case with venerable Java UUID Generator (JUG): my first true Open Source project.
Although it is not exactly the first thing that I ever released as open source (that would be something called "NetReaper", or perhaps "DLR", both from late 90s -- few have ever heard of them -- heck, even "Fractalizer" is older!), and much less the first piece of software I have released (shareware lib/app that compressed Amiga Soundtracker files using delta compression is probably the first one, from late 80s!), I count it as basically starting point of my open source "career".

So what is happening? Well: there is the new JUG project page (at the OS darling GitHub); matching skeletal JUG product page at FasterXML; and of course the brand new JUG users discussion group (java-uuid-generator-users) at Google Groups, waiting for users to talk about it. And probably most interestingly, actual development effort to produce third major version, 3.0.

Given that the project has spent past 5 or so years changing very little, why is there new development effort? Mostly because JDK finally caught up with JUG, so to speak -- JDK 1.6 finally has a pure Java method of accessing Ethernet interface MAC addresses -- but partly also because of other niceties that can now be added (java.util.UUID was added in JDK 1.4; which was not the stable version at the time of writing JUG 2.0). And finally, there's quite a bit of clean up that would be nice to do if I was to work on the code.

Given above, here are the modest goals for version 3.0

  • Add convenient support for using local Ethernet address, without using JNI library (requires JDK 1.6); and remove legacy code that was needed for JNI
  • Change UUID type to use from JUG-specific to java.util.UUID (also allows removing quite a bit of code)
  • Build/deployment changes: change build to Maven (including releasing builds to Maven repos); jars built as OSGi bundles as well
  • SCM changes: move from Safehaus/svn to GitHub/git
  • Improve API to avoid relying heavily on singletons; streamline for simpler (and perhaps more elegant) access
  • Add support for one "new" UUID generation method (using SHA-1 instead of MD5 for name/hash based generation)
  • Maybe even write a simple tutorial for using the lib!

Which is just to say, renovate the package so it does not feel quite so 2002 any more (which is when it was written originally). :-)

Monday, May 17, 2010

Finally: Java JSON Schema validator; based on Jackson

Ok here are some good news for Java developers who use (or might like to use) JSON, but are bothered by lack of data format validation options: Nicolas Vahlas has written the first Java JSON Schema validator, and it is available from Gitorious as project json-schema-validator.

I have not yet have time to dig deep into it, but there all signs for it being so-called Good Stuff. Not just because it is based on Jackson -- although proper reuse of existing solid components is a general good sign -- but because description gives an idea of author being someone actually knows what he is doing.

So please check it out if said functionality seems at all interesting: the best way to ensure it becomes a first-class tool (and maybe even help JSON Schema standard improve along the way) is to use it, give feedback, and get the whole flywheel-of-virtue (aka virtuous cycle) thing going on. That's how things like Jackson and Woodstox became good: feedback is the amplifier of open source productivity.

Ok, enough raving: I'm off to get the sources for bit of closer look. :-)

Thursday, May 13, 2010

Happy First Birthday, Jackson the JSON processor!

Time sure flies when you are having fun: I just realized thatJackson JSON processor had its first birthday, if we use its 1.0 release's date (of May 9th, 2009) as the reference point.

And how far has Jackson community come? Here are some interesting statistics, mostly provided by good old Google Analytics:

  • 10,000 monthly visits to Jackson wiki; with 33,000 page views (getting close to half million page views per year)
  • 5,000 monthly visits to Jackson Javadocs; with 17,000 page views (200k on annual basis)
  • close to 4,500 downloads (== visits toJackson Download page) -- meaning about 50k direct downloads on annual basis; and many more if access via Maven was included (wonder how could this be tracked)

It is fascinating how far and how fast Jackson has gone: currently its downloads beat Woodstox by factor of 4:1, for example, although Woodstox has been the leading high-performance Java XML parser for years now -- difference has to do with both declining popularity of XML (compared to JSON), and because Woodstox is more commonly bundled with frameworks, whereas Jackson is quite pleasant to use directly. Furthermore looking at trends, it looks like "Jackson traffic" has doubled or tripled over past 8 months or so.

Of course, traffic numbers are not quite as interesting as more applicable things -- number of users, and even more importantly, amount of functionality Jackson offers. But still, above numbers give some guidance as to growing popularity of Jackson, as well as of JSON as THE dominant data format on Java platform.

Wednesday, April 28, 2010

Making Java Reflection field access 40 times faster

Think it can not be done? Think again!

Here is a useful nugget of information that should be common knowledge among performance-conscious Java developers:but based on code I've seen in the wild it might not yet be, hence this entry.

Basically, if you just do this:

  Field f = MyBean.class.getDeclaredField("id");
  f.set(beanInstance, valueForField);

performance stinks -- setting value is about hundreds of times slower than direct field access. But if you add this little call:

  f.setAccessible(true);

in there, overhead is drastically reduced. In a simple micro-benchmark running on my old desktop speed difference is 40x, and while YMMV, it will be an order of magnitude or more and this ratio does not seem to improve with new JVMs (has been steady with 1.4, 1.5 and 1.6). This actually takes overhead down enough so as to make reflection-based access "fast enough" for most use cases: Jackson for example just uses it and does not bother with byte-code generation to create most optimal access (but who knows? maybe it will one day).

So what is the difference? Access checks that would be done by default are heavy-weight, as can be seen from profiler stack traces and JDK sources. And all setAccessible() method does is set a boolean flag that will by-pass these checks. Works for Methods and Constructors as well, although with slightly less pronounced results.

Anyway, thought others might find this useful.

Related Blogs

(by Author (topics))

Powered By

Powered by Thingamablog,
Blogger Templates and Discus comments.

About me

  • I am known as Cowtowncoder
  • Contact me at@yahoo.com
Check my profile to learn more.