6

Having recently had reason to peruse the Nullable documentation, I noticed that the definition of Nullable looks like:

public struct Nullable<T> where T : struct, new()

I was of the (mis?)understanding that structs always have a public parameterless constructor, if this is correct, what does the new() type constraint add here?

Community
  • 1
  • 1
Rich O'Kelly
  • 41,274
  • 9
  • 83
  • 114
  • As I imply in my answer, `Nullable` actually has the constraint `where T : struct, ValueType, new()`, not that that extra redundancy seems to add anything at the moment either. (I.e. the IL is ``Nullable`1``) – Mark Hurd Sep 20 '12 at 10:51

3 Answers3

3

For struct new doesn't make sense. For classes it does.

In your case it is a redundant.

public T FactoryCreateInstance<T>() where T : new()
{
return new T();
}

It make sense to specify new constraint in a case like above but not when it is already constrained to be struct.

Parameter less constructor for value types is a C# restriction and not a CLI restriction. Maybe this is why is it specified redundantly to leave some wiggle room for future.

Saeed Amiri
  • 22,252
  • 5
  • 45
  • 83
parapura rajkumar
  • 24,045
  • 1
  • 55
  • 85
  • Why do you think new() doesn't apply to structs? According to the quote I gave in my answer, and the fact that you dimension structs using the new keyword I would think it wouldn't make any difference. I haven't tried it yet though so I'm just curious if you know this for a fact? – Brandon Moore Nov 19 '11 at 00:46
  • I tried it and having just : struct (without the new()) is sufficient to reference have code like x = new T() within your generic. – hatchet - done with SOverflow Nov 19 '11 at 00:57
  • The existence of a do-nothing default parameterless constructor isn't a CLI restriction, but when the CLI allocates space for a struct, it doesn't call *any* constructor on the elements thereof. Microsoft probably thought that since anything that could be done with a constructor could also be done with an instance member, there wasn't much need for the latter. They may have been mostly right, except that in some cases involving generics, a constructor might have been able to offer slightly better performance. – supercat Nov 19 '11 at 19:03
1

Just noting this is valid, verifiable IL (i.e.

 .class public sequential ansi sealed StructNewStruct`1<valuetype .ctor ([mscorlib]System.ValueType) T>
     extends [mscorlib]System.ValueType

compiles, as does the simpler

 .class public sequential ansi sealed StructNewStruct`1<valuetype .ctor T>
     extends [mscorlib]System.ValueType

) but I don't yet have code that does anything different for these that a simple where T:struct (or (Of T As Structure) in VB.NET and <valuetype T> in IL) provides.

Specifically, Nullable structs are already not allowed for any generic argument with a simple struct constraint. (It does seem Nullable objects are classes for almost all purposes except storage.)

So, in summary, Nullable<T>'s current (equivalent of) where T:ValueType, struct, new() seems to currently be identical to where T:struct.

For your information I used my updated DotLisp that allows the creation of generic types (just using MakeGenericType) to attempt to create a type of StructNewStruct<t> and StructStruct<t>(*) for all types in all assemblies of the 4.0 Framework that load without me trying to load "unusual" assemblies (e.g. System.Web may not have been loaded). (If there are any "special" types in "obscure" framework assemblies let me know and I'll ensure they're loaded and tried.) All types succeeded or failed the same with both structures.

(*) StructStruct<T> where T:struct

Mark Hurd
  • 10,665
  • 10
  • 68
  • 101
  • Nullable types behave nothing like classes, outside the facts that compilers will allow `null` to be type-coerced into a default-valued `Nullable` for any non-nullable value type `T`, and nullable types (annoyingly) do not satisfy a struct constraint. Note that casting a non-null class-type storage location to an interface type will simply reinterpret a reference to the existing object, but every cast of a non-null `Nullable` to an interface type will yield a new object of the heap type corresponding to `T`. – supercat Sep 18 '12 at 15:27
  • @supercat Perhaps I am slightly exaggerating the `class`-likeness of `Nullable` because of the non-satisfaction of `struct` constraints. Note that `Nullable<>` itself does not implement _any_ interfaces so a conversion is always required. – Mark Hurd Sep 19 '12 at 02:42
  • It's true that Nullable doesn't implement any interfaces, but a `Nullable` may (syntactically) be passed to any method expecting an interface type which `T` implements. – supercat Sep 19 '12 at 14:37
  • @supercat I previously had a comment here suggesting the Explicit `Nullable` to `T` was implicitly applied by VB.NET (and C#), but that was based on me using LINQpad 4 effectively with `Option Strict Off` (and not testing C# at all). So now you've shown me a feature that seems surprising with VB's `Strict On`! – Mark Hurd Sep 20 '12 at 01:27
  • I have now asked a [question](http://stackoverflow.com/q/12505053/256431) confirming VB.NET's "decision" to implicitly convert interfaces with `Option Strict On`. – Mark Hurd Sep 20 '12 at 01:49
  • 1
    I'm reaching the conclusion that the extra constraint doesn't add anything, however, it doesn't detract anything either which is why the compiler team have included it to allow a little more flexibility in the future. Good answer, thanks +1 – Rich O'Kelly Sep 20 '12 at 11:40
  • @MarkHurd: All value types will satisfy a `new` constraint (a fact which is useful). Anything which satisfies a `struct` constraint will also satisfy a `new` constraint; although neither vb.net nor C# seems to allow a redundant `new` constraint for a generic type which also has a `struct` constraint, that doesn't mean things written directly in CIL couldn't combine them. It is possible to use a generic type with a `new` constraint as a constraint on a type which also has a structure constraint, even though the only way both constraints would be met would be for both to be the same struct. – supercat Sep 20 '12 at 14:19
  • @supercat The first part of your last comment corresponds to my answer. I don't understand the point of your last sentence. – Mark Hurd Sep 21 '12 at 03:50
  • @MarkHurd: Even though the compiler will not explicitly allow a `new` constraint and a `struct` constraint to be specified *directly* on the same generic type, it will not complain if a `struct` constraint is applied to a type which *indirectly* has a `new` constraint on it (by virtue of being constrained to a generic type which does). I think the only way a struct can satisfy a constraint to a generic type which has a `new` constraint is if the struct is being constrained to itself (though on second thought, I'm not 100% sure, since... – supercat Sep 21 '12 at 14:13
  • ...I know that it's possible for COM objects to be declared as interface types and yet be instantiable; I don't think any such types can satisfy `new` constraints, since one can't simply `new()` them, but I don't know exactly what can be done. – supercat Sep 21 '12 at 14:18
1

It doesn't have to have a parameterless constructor, and even if it does have one it doesn't have to be a public one. I believe that "new()" requires it to have both these things.

Edit: Yup, as per the MSDN documentation: "The new constraint specifies that any type argument in a generic class declaration must have a public parameterless constructor."

Brandon Moore
  • 8,590
  • 15
  • 65
  • 120
  • 1
    See the struct spec: Struct constructors are similar to class constructors, except for the following differences: Structs cannot contain explicit parameterless constructors. Struct members are automatically initialized to their default values. A struct cannot have an initializer in the form: base (argument-list). – Rich O'Kelly Nov 22 '11 at 11:19
  • Ah... that shows you how long it's been since I've tried to create a struct. Thanks for that correction. +1 – Brandon Moore Nov 22 '11 at 20:59
  • @rich.okelly: What makes structs different from classes isn't that fields are initialized to default values when they come into existence (class fields are initialized to default values when class objects come into existence), but rather that rather that since struct-type storage location *is* a struct-type instance, a struct instance comes into existence as soon as the storage location does. Creating an array `ClassType[100]` doesn't create any instances, but creating a `StructType[100`] creates 100 new struct instances. – supercat Sep 19 '12 at 14:49
  • @supercat My comment was intended to point out that structs *always* have public parameterless constructors contrary to what this answer states. In response to your comment, yes I am aware of this and to expand upon it slightly - creating an array `ClassType[100]` actually allocates memory for 100 pointers to `ClassType` whereas an array `StructType[100]` will allocate memory for 100 `StructType`s. What you say is correct since allocating memory for a struct is equivalent to creating one. – Rich O'Kelly Sep 20 '12 at 11:37
  • @rich.okelly: Structures always have a public parameterless constructor which can be called, but never (in C# or vb.net at least) have a parameterless constructor which actually does anything. This design was predicated upon the fact that it would be confusing to have `default` be something which wasn't `null` and wasn't `new T()`. I don't know if the CLS spec requires that languages provide a means of explicitly calling a parameterless constructor on externally-defined structs, since there's nothing in CIL which would prevent a struct having a non-trivial parameterless constructor. – supercat Sep 20 '12 at 14:51