Immutable Classes

C

Chris Mullins

I've got some classes that I've built that currently require far too many
locks when they're running in a multi-threaded environment. To get around
this, I'm looking to make these classes immutable. I'm also trying to be (as
any good programmer) as lazy as possible about the approach tha tI take.

I have a class (XmppId) that has roughly the same properties on it you would
expect of an email address.

I would like to be able to say,
"public class ImmutableXmppID : Immutable<XmppId>{}"

I would also like to take the same approach as strings, with a global Intern
list and precalculated hashes in order to help with performance.

The issue so far is that this seems to be well beyond the scope of what
Generics can do. The only option for doing this that I can see is to build a
CodeSmith template, or even a custom piece of Code Generation for the
CodeDOM, and then do it.

Anyone done any signifigant work with immutable classes, and have any gems
of wisdom they're willing to pass along?
 
D

David Browne

Chris Mullins said:
I've got some classes that I've built that currently require far too many
locks when they're running in a multi-threaded environment. To get around
this, I'm looking to make these classes immutable. I'm also trying to be
(as any good programmer) as lazy as possible about the approach tha tI
take.

I have a class (XmppId) that has roughly the same properties on it you
would expect of an email address.

I would like to be able to say,
"public class ImmutableXmppID : Immutable<XmppId>{}"

I would also like to take the same approach as strings, with a global
Intern list and precalculated hashes in order to help with performance.

The issue so far is that this seems to be well beyond the scope of what
Generics can do. The only option for doing this that I can see is to build
a CodeSmith template, or even a custom piece of Code Generation for the
CodeDOM, and then do it.

Anyone done any signifigant work with immutable classes, and have any gems
of wisdom they're willing to pass along?

Why are trying to build an immutable wrapper around an existing type? If
you want immutable type, why not just design it that way?

An immutable type just one with no public fields, no methods that alter its
internal state and no methods that return references to non-immutable state
variables.

In practice just pass all the fields into the constructor, set them there
and compute the hash. EG:

class XmppId
{

readonly string name;
public string Name
{
get { return name; }
}

readonly string domain;
public string Domain
{
get { return domain; }
}

readonly int hashCode;
public override int GetHashCode()
{
return hashCode;
}

public XmppId(string Name, string Domain)
{
domain = Domain;
name = Name;
hashCode = domain.GetHashCode() | name.GetHashCode();
}

}

David
 
C

Chris Mullins

David Browne said:
Why are trying to build an immutable wrapper around an existing type? If
you want immutable type, why not just design it that way?

Well, this is partly where the laziness comes in, and partly where the real
problem is more complex than the simple 1 class case I described.

I have a number of classes to which I would like to do this, and I would
like to have Interning come along for the ride, so as to save me quite a bit
of memory.

Our XMPP server ends up with lots and lots of these XmppId classes stored
all over the place, and the Interning will save us huge amounts of memory.
For example, a users roster is composed of (mostly) these ID's, and users
often have 10 to 100 other users in their roster. Multiply this by 50k
simultanious users online, and that's alot of (mostly) duplicated XmppId
classes.

It also turns out that an XmppId class is really a composite class made up
of a Server ("coversant.net"), a User Name ("cmullins"), and a resource,
"work". Ideally each of these smaller classes to also be immutable and
Interned. This way all of the cases for: (e-mail address removed)\work, user2,
user3, user4 doesn't waste memory on the server portion of the ID ('cause
it's Interned).

There are also combinations of these classes. For example BareXmppID is a
user@server with no resource, and is a class in it's own right, as there is
signifigant business logic around it.
 
G

Greg Young

I would generate at runtime an "immutable proxy" ... this will obviously not
help in all cases but atleast for getters/setters as you discuss ... You
could also add something such as an [immutable] attribute so it could
determine which methods were allowed to be called.

Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung
 
G

Greg Young

I should add that while this meets your laziness needs it may not work
really well for your performance needs.
Greg Young said:
I would generate at runtime an "immutable proxy" ... this will obviously
not help in all cases but atleast for getters/setters as you discuss ...
You could also add something such as an [immutable] attribute so it could
determine which methods were allowed to be called.

Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung
 
C

Chris Mullins

Unfortunatly the performance is more important than my laziness - so I'll do
it the hard way.

Anything I can come up with, I'll add to my blog. I suspect, long term,
other people would take this approach in high-performance systems if it were
easier to do.

--
Chris

Greg Young said:
I should add that while this meets your laziness needs it may not work
really well for your performance needs.
Greg Young said:
I would generate at runtime an "immutable proxy" ... this will obviously
not help in all cases but atleast for getters/setters as you discuss ...
You could also add something such as an [immutable] attribute so it could
determine which methods were allowed to be called.

Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung

Chris Mullins said:
Why are trying to build an immutable wrapper around an existing type?
If you want immutable type, why not just design it that way?

Well, this is partly where the laziness comes in, and partly where the
real problem is more complex than the simple 1 class case I described.

I have a number of classes to which I would like to do this, and I would
like to have Interning come along for the ride, so as to save me quite a
bit of memory.

Our XMPP server ends up with lots and lots of these XmppId classes
stored all over the place, and the Interning will save us huge amounts
of memory. For example, a users roster is composed of (mostly) these
ID's, and users often have 10 to 100 other users in their roster.
Multiply this by 50k simultanious users online, and that's alot of
(mostly) duplicated XmppId classes.

It also turns out that an XmppId class is really a composite class made
up of a Server ("coversant.net"), a User Name ("cmullins"), and a
resource, "work". Ideally each of these smaller classes to also be
immutable and Interned. This way all of the cases for:
(e-mail address removed)\work, user2, user3, user4 doesn't waste memory on
the server portion of the ID ('cause it's Interned).

There are also combinations of these classes. For example BareXmppID is
a user@server with no resource, and is a class in it's own right, as
there is signifigant business logic around it.
 
G

Greg Young

Just threw this one at jd but I will mention it to you as well .. remember
that on a 32 bit platform that reference still costs you 4 bytes (8 on 64)
so on a 64 bit architecture it may very well cost you more to use this than
say a fixed char in a struct ... or an array of such and an in16 or int32
that you keep as an index.

Cheers,

Greg

Chris Mullins said:
Unfortunatly the performance is more important than my laziness - so I'll
do it the hard way.

Anything I can come up with, I'll add to my blog. I suspect, long term,
other people would take this approach in high-performance systems if it
were easier to do.

--
Chris

Greg Young said:
I should add that while this meets your laziness needs it may not work
really well for your performance needs.
Greg Young said:
I would generate at runtime an "immutable proxy" ... this will obviously
not help in all cases but atleast for getters/setters as you discuss ...
You could also add something such as an [immutable] attribute so it could
determine which methods were allowed to be called.

Cheers,

Greg Young
MVP - C#
http://codebetter.com/blogs/gregyoung


Why are trying to build an immutable wrapper around an existing type?
If you want immutable type, why not just design it that way?

Well, this is partly where the laziness comes in, and partly where the
real problem is more complex than the simple 1 class case I described.

I have a number of classes to which I would like to do this, and I
would like to have Interning come along for the ride, so as to save me
quite a bit of memory.

Our XMPP server ends up with lots and lots of these XmppId classes
stored all over the place, and the Interning will save us huge amounts
of memory. For example, a users roster is composed of (mostly) these
ID's, and users often have 10 to 100 other users in their roster.
Multiply this by 50k simultanious users online, and that's alot of
(mostly) duplicated XmppId classes.

It also turns out that an XmppId class is really a composite class made
up of a Server ("coversant.net"), a User Name ("cmullins"), and a
resource, "work". Ideally each of these smaller classes to also be
immutable and Interned. This way all of the cases for:
(e-mail address removed)\work, user2, user3, user4 doesn't waste memory
on the server portion of the ID ('cause it's Interned).

There are also combinations of these classes. For example BareXmppID is
a user@server with no resource, and is a class in it's own right, as
there is signifigant business logic around it.
 
C

Chris Mullins

Yea, a Flyweight pattern is pretty much just what the doctor ordered.

In terms of implementing an interned, immutal set of classes that's the way
to go. I just have to figure out the priority for this project in my time
schedule over the next few months.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top