views:

378

answers:

11

Hi.

I wanted to ask what is the idea behind the fact that System.String doesn't contain parameterless constructor.

Because of this you cannot use this type when there is new() constraint.

UPDATE

Why do you think that new string() is useless and e.g. new int() is not useless. I really cannot see the difference. I really would like to be able to use a new() constraint on string, since what I'm expecting is String.Empty.

UPDATE2

I know that int is a value type and all value types have default parameterless constructor. I was referring to @John Saunders answer (and similar answers) that were stating that saying new String() basically doesn't do anything useful. So if new String() doesn't mean anything useful what is so useful about new int()? I also understand that it is important for value types to have default parameterless constructors. What is more I think that it would be really nice for string to have a default parameterless constructor. Lack of a parameterless constructor means for me that an object simply cannot exist without a parameter that will initialize it. In my opinion string doesn't need any parameter because it could be empty. I asked this question because I wanted to know if there is some important reason for string not having parameterless constructor or it's just design or sth else.

UPDATE3

I guess it will be the last update since it looks more like a blog post than a question. In java strings are also immutable and new String() is perfectly legal. However, documentation for parameterless constructor says:

Initializes a newly created String object so that it represents an empty character sequence. Note that use of this constructor is unnecessary since Strings are immutable.

UPDATE4

Ok, last update ;) I have to agree with John Saunders. I was using code that had new() constraint and it worked nicely for custom classes. Then, my colleague need to change the code for ints and it was ok. Then change it for string and we had a problem. When I now think about it I guess the code we are using needs to be changed to reflect that we need scalar types not classes that have parameterless constructor. All that said, I still think it's a bit inconsisent that you can write new int() and you are unable to write new string() (yes, I understand that int is a value type ;)). Thanks for all your answers!

Thanks in advance for help.

+19  A: 

If you could use

string s = new string();

What would you do with it? Strings are immutable.


Some readers have thought I was saying that a parameterless string constructor would be useless. That's not what I meant. I meant that the empty string created from such a constructor would be useless in the rest of the code.

Keep in mind what the OP said he wanted to do:

public void SomeMethod<T>() where T : new()
{
    var t = new T();
    // Do _what_ now?
}

// Call:
SomeMethod<string>();

I don't see what you could do with t after it was constructed.

John Saunders
So you never use String.Empty then?
Joe Gauterin
@Joe Gauterin - I don't think Saunders is saying anything about String.Empty. He is saying that it doesn't make sense to have a parameterless constructor for the string class. Either you set a default value, string.empty, or null.
JonH
@John: new String() should reasonably return String.Empty. I've been burned several times because I wanted to pass a string into a generic method `DoSomething<T>(T t) where T : new()`, but I can't work with strings because they don't have a default constructor.
Juliet
@JonH: Clearly it does make sense to have a parameterless constructor, as the questioner has a use case for one. It doesn't help that the default value all class types is null, not String.Empty.
Joe Gauterin
@Juliet: Why? That would create lots of empty strings to be garbage collected as it would create a new string instance just to have an empty string. I'd rather a single instance that meant "the empty string" than lots just for the convenience of using `where T : new()`. If you want a `string` type that has that ability, create your own wrapper or use `StringBuilder` instead. Square peg, round hole - don't go chiseling the peg.
Jeff Yates
In my opinion if there is new int(), there is no reason for lack of new string()
empi
@Jeff: if I don't want to create lots of empty strings, I'll create one instance and cache it locally in my method. To name one example, I needed to write some code for my company which creates a new object and initializes its entire object graph to a non-null value. Every object in the graph was guaranteed to have default constructors, except for strings which were handled as a special case. Microsoft reasons that String.Empty "saves the developer from themselves" in case they repeatedly new up empty strings, but the end result actually harmed the design of my code.
Juliet
@Juliet: But it's easy to write your own struct that wraps string and does what you want. Where's the hassle? I think the framework justifiably restricts string construction in this manner, placing the onus on the developer to write the wrapper if they wish to circumvent it.
Jeff Yates
@empi: int is a value type. Strings are a special case reference type. They are very different.
Jeff Yates
I downvoted because this is not an answer, but a comment on the question.
Joren
@Joren: no, it's the answer. it doesn't have a parameterless constructor because it wouldn't make any sense in an immutable type.
John Saunders
@Juliet: that's a damned odd use-case. What's it for? Security? Are you aware of the SecureString class? It has a parameterless constructor.
John Saunders
@John: the use case above assisted with testing: we had lots of classes which mapped objects of type A to type B. We new'd up an instance of A with its object graph populated, mapped it to B, and if B had any null fields, something wasn't copied over, so the test fails. Without populating the object graph, it isn't possible to tell the difference between copying a null from A to B vs not copying from A to B at all.
Juliet
"I don't see what you could do with t after it was constructed." -- should it matter if T represents a string or a non-BCL type? No, so you use it the same way you use any other method with the new constraint. You can return a type T, assign it to a property, add a constraint that T implements IComparable, new up an object in case null is an invalid value, etc. I'm just having a hard time seeing the argument that default string constructors **never** have a purpose.
Juliet
@Juliet: Your unit test case is pretty obscure: you want to prove your mapping method copies something non-null, so you need every property to be non-null, so you set each property to the result of calling its default constructor. So the answer to my question of what you're going to do with it is "compare it to null". Have you tried setting each property to `default(T)`?
John Saunders
Just to let you know, I have removed my downvote, because I think you've added enough for the answer to be worthwhile.
Joren
A: 

What would

String s = new String();

give you over

String s = String.Empty;

or

String s = null;
Robin Day
Why would new'ing up an instance of an object ever give you a null?
Juliet
@Juliet - if the object is a ref. type and belongs to a class it defaults to null.
JonH
@Juliet, I realise I wan't being clear. What I meant was if you don't have anything to pass to the constructor then you probably want it to be either empty, or null.
Robin Day
+3  A: 

What is a string without an actual string?

You can do this:

String s = "hello world";

And once you have the string you cannot alter that specific string (strimgs are immutable). If you are looking to declare an empty string then just do:

string s = string.empty
JonH
+1  A: 

From http://msdn.microsoft.com/en-gb/library/system.string.aspx

A String object is called immutable (read-only) because its value cannot be modified once it has been created. Methods that appear to modify a String object actually return a new String object that contains the modification. If it is necessary to modify the actual contents of a string-like object, use the System.Text.StringBuilder class.

So a parameterless constructor wouldn't make sense.

dbemerlin
Immutability doesn't at all imply that an object shouldn't have a parameterless constructors. Case in point: every value type is immutable and has a parameterless constructor (i.e. `DateTime d = new DateTime()`), and every many implementations of immutable data structures will represent an empty node with a parameterless constructor.
Juliet
Yep - value types are required to be both immutable and to have a parameterless constructor.
Joe Gauterin
Value types are not immutable. If you create a struct you can change it's properties (struct Foo { public int bar; } Foo foo = new Foo(); foo.bar = 1; foo.bar = 2; ...). This is not possible for strings. Properties that return a value are immutable however as changing the returned value does not affect the original value as only a copy is returned from the property.
dbemerlin
@dbemerlin: you *can* make a mutable value type, but almost everyone agrees they're evil and use of them in any serious production code is grounds for flogging.
Juliet
A: 

All empty Strings are the same. Why do you want to create one? You can use String.Empty or simply "".

codymanix
+2  A: 

I'm guessing you want to be able to define a class that's something like this:

public class SpecializedCollection<T> where T : new() {
    private List<T> _startingItems;

    public SpecializedCollection(int startingSize) {
        _startingItems = new List<T>(startingSize);
        for (int i = 0; i < startingSize; ++i)
            _startingItems.Add(new T());
    }

    // ... lots more code
}

Am I right? If you want this to be more flexible, to allow for types that may not have a default parameterless constructor, you can always do this:

public class SpecializedCollection<T> {
    private List<T> _startingItems;

    // note: here we leave it up to the caller to specify
    // how T objects will be instantiated
    public SpecializedCollection(int startingSize, Func<T> generator) {
        _startingItems = new List<T>(startingSize);
        for (int i = 0; i < startingSize; ++i)
            _startingItems.Add(generator.Invoke());
    }
}

Then you could create a SpecializedCollection<string> like so:

var strings = new SpecializedCollection<string>(10, () => string.Empty);

Of course, if you wanted to offer a default constructor that would attempt to construct objects using a parameterless constructor for T, you could always overload the constructor:

public SpecializedCollection(int startingSize)
    : this(startingSize, Activator.CreateInstance<T>()) { }

The above wouldn't work for string, of course, but it would for any class with a parameterless constructor (i.e., anything that would've worked with the old where T : new() constraint).

Dan Tao
+1  A: 

It's a common problem in generic code. C++ solves it with template specialization, but C# doesn't support that.

It can't be done cleanly in C# though - your best bet is to use the class constraint instead, then use reflection based hack to default construct a T or use String.Empty if T is System.String. You'll lose compiler checking for using other classes which aren't default constructable though.

Here's another option:

class MyClass<T> where T : class
{
    public MyClass(T default)
    private T m_default;      
};

MyClass<object> instance = new MyClass<object>(new object());
MyClass<string> instance = new MyClass<string>(String.Empty);

And another:

class MyClass<T> where T : class
{
    static SetDefault(T def)
    { 
       s_default = def;
    }
    static T s_default;      
};

MyClass<object> instance = new MyClass<object>(new object());
MyClass<string> instance = new MyClass<string>(String.Empty);
Joe Gauterin
A: 

"[Why doesn't] System.String...contain [a] parameterless constructor?"

Because that's the way it was designed. As you can see from the variety of answers and opinions here, there's not even a clear consensus on the need or implementation of a parameterless constructor. Obviously, it's technically possible to have a default constructor that initializes to String.Empty - so either the BCL team didn't think of it (unlikely), or didn't feel it was a worthwhile scenario (likely). FWIW, I agree - I don't see a reason why a default ctor on string is important.

"Why do you think that new string() is useless and e.g. new int() is not useless. I really cannot see the difference."

The difference is that int is a ValueType. ValueTypes are required to have a default constructor, and it initializes the type to a default value. string is a reference type - it already has a default value - null (the same as all other reference types).

Of course, you disagree - you have a specific scenario that you feel is best implemented with a default ctor on string. Without knowing specifics about your scenario, it's hard to comment on it intelligently. But, my guess is that you're dealing with primitive obsession. If string.Empty makes sense for your particular data, then you should probably have a class around it. It's default constructor can initialize a string.Empty.

E: Why primitive obsession?

I was going to write about ORMs or other mappers (the few places that I can think of that where T:new() is useful) and how, instead of trying to map strings, you should be using a custom business object. But, after doing some example code - I'm pretty stuck. I can't think of any scenario that makes sense with a new string() == string.Empty.

Mark Brackett
Primitive obsession means you create a method like `PersistCustomer(customerId, customerFirstName, customerLastName, customerPhone)` instead of `PersistCustomer(customer)`. I don't think default constructors on objects counts as primitive obsession.
Juliet
@Juliet - Yes, that is an example of primitive obsession - thanks. ;) The larger picture is that you're trying to force meaning onto primitives (oh look, it's an int named customerId - must be a reference to a customer!). I'll update with a bit more on *why* I'm guessing the OP is doing that...(note, though - that it is a guess. I have no knowledge of why he wants a default ctor)
Mark Brackett
+1  A: 

Specifically addressing how to avoid the new() constraint problem when you're working with generic types:

Include the following field, property, and method:

private readonly Func<T> _defaultValueFactory = (Func<T>)DefaultT;
private Func<T> DefaultValueFactory
{
    get
    {
        return _defaultValueFactory;
    }
}

private static T DefaultT()
{
    return default(T);
}

Also include a constructor for your type that takes a Func<T> defaultValueFactory.

Wherever you normally use new T(), use DefaultValueFactory() instead.

280Z28
+5  A: 

Why do you think that new string() is useless and e.g. new int() is not useless.

Let's go back to basics and talk about reference and value types.

When you create an int, long, point, or whatever, the value type is allocated on the stack -- so an int reserves 4 bytes on the stack, long is 8 bytes, and so on. The stack space reserved for the value type is zero'd out -- its not possible ever to refer to value types address on the stack and get a null. So default constructors on value types probably result more from quirks in stack allocation than usefulness (maybe someone at MS could give more insight).

In any case, I think System.String lacks a default constructor because of lousy API design.

Immutable objects -- enumerables in particular -- almost always expose a default constructor to instantiate an empty collection.

I think Microsoft had good intentions: it is better to use "" or String.Empty whenever you need an empty string because they're interned, and not so useful to new up a new String() everytime -- but it comes across to me as Microsoft's way of "saving the developers from themselves".

(Thanks Microsoft, I appreciate your paternalistic hand-holding, but I'm perfectly capable of taking care of myself. If I don't want to create multiple instances of the same object, I'll cache it just like I do for the bagillion other types with a default constructor.)

For now, you need to treat objects without default constructors as a special case from everything else. Rewrite

public void DoSomething<T>() where T : new() { ... }

As two methods:

public void DoSomething<T>() where T : new() { DoSomething(() => new T()); }

public void DoSomething<T>(Func<T> constructor) { }

Clients to your code should decide which function to call for themselves.


Now someone looking at the code above might ask why you'd pass a constructor instead of an actual object into the method, i.e.

public void DoSomething<T>(T obj) { ... }

There might be reasons, for example if the constructor method isn't guaranteed to be called. I worked complex winform app where clicking buttons or menu items would pop up a form -- or, if the form was already open, we'd focus it instead. So we had something like:

public T ShowForm<T>(Func<T> constructor) where T : Form
{
    T res = default(T);
    foreach(Form f in Application.OpenForms)
    {
        if (f is T)
        {
            res = (T)f;
            break;
        }
    }

    if (res == null)
        res = constructor();

    res.Focus();
    return res;
}

We couldn't use the new constraint since some forms had non-default constructors, so the strategy above ultimately worked out really well and saved us the trouble of creating a ton of factory classes.

Juliet
+1, nice solution. However, it works only if T is a type paramter for a generic method, not for a generic class
Thomas Levesque
You can certainly use it for generic classes: `DoSomething(() => new List<int>());`
Juliet
A: 

Int32 is a struct. Structs ALWAYS have a parameterless constructor. It has nothing to do with it's usefulness - even if Microsoft decided that Int32's parameterless constructor is completely and utterly useless, there is absolutely nothing they could do about it. And if they wanted to change the behavior of structs now, it would be a huge breaking change. Turning Int32 into a class is also not feasible at all as there is a reason why .net supports both Value and Reference type (I hear from the Java guys that the fact that Integer is a class causes some problems, but I can't comment on that really).

String on the other hand is a class. For classes, you can control whether or not is has a parameterless constructor, so here it was possible to see that it's useless and omit it.

Michael Stum