0

I am designing a class that will contain a somewhat too big number of DateTime fields. It will be convenient to use this set of fields separately in some functions. Also, the meaning and way of usage of this set - what I can describe as a "complex timestamp", fits value type semantics better than object semantics IMHO. So I think of uniting these fields in one structure. An important detail is that many of these fields can be null as by the business logic model semantics. I would also prefer if it and its members would not be ever passed outside the class by reference (though this is a subjective idea of mine, perhaps passing this by reference would do no harm ever actually).

For example (not exactly my case, but a seemingly relevant illustration)

public struct ProjectTaskDateTimeStamp
{
    DateTime  Drafted // I don't mind if this field is made nullable too perhaps
    DateTime? Proposed
    DateTime? Approved
    DateTime? Finished
    DateTime? Archived
}

I may also decide to make this-typed property of the class nullable too.

How bad/reasonable idea this is and why? Should I make this a class instead and why?

In what actual ways (including memory representation and management, behaviour of itself, its members and other language/runtime subjects that will be interacting with it and passing/sharing it among each other, language semantics) does a structure containing nullable fields (and assigned to a nullable variable perhaps) differ from a class and from a pure (containing value type fields only) structure?

Ivan
  • 63,011
  • 101
  • 250
  • 382
  • 1. It is generally recommended for structs to be immutable. Here you have clearly a mutable struct, I strongly advise to use class. 2. There is no concept of "pure" structure. 3. Nullable types are structs themselves so you have struct of structs so to say. 4. A structure containing nullable fields differs from a class exactly the same way any other struct differs from a class. – Andrey Mar 12 '17 at 18:15
  • @Andrey 1. "Here you have clearly a mutable struct" - not really, it is initialised once and never modified (but can replaced, the way we do when "modifying" an immutable value in functional languages). The class that will contain it is never modified too (except at the initialisation time) but it is clearly too big and complex to be made a struct. – Ivan Mar 12 '17 at 18:21
  • @Andrey 2. I know there is no such concept in general but I just needed a word to represent what I mean concisely. Perhaps my decision to introduce it is inadequate and makes no sense as based entirely on insufficient/wrong understanding of the subject, that's why I am asking the question. – Ivan Mar 12 '17 at 18:25
  • it is mutable, whether it will be mutated or not is another question. If it is immutable then you don't need really nullable fields. Once your project is approved you need to so some modifications. – Andrey Mar 12 '17 at 18:32
  • @Andrey "If it is immutable then you don't need really nullable fields" - why? I use null more in sense of the functional "nothing" (which fits quite well (is an essential concept actually) in purely-immutable functional programming paradigm) in this case, meaning semantics close to "not applicable". I might introduce the `Option` monad type instead but I just prefer to keep it simple and avoid introducing custom stuff for what can be done with standard types with seemingly no drawbacks. – Ivan Mar 12 '17 at 18:45

1 Answers1

1

How bad/reasonable idea this is and why?

I will ignore memory and representation issues for a moment. Semantically, it sounds to me like you would be better off declaring an enum of the timestamp descriptions:

enum TimestampType { Drafted, Proposed, Approved, Finished, Archived };

And then your data structure would basically be a dictionary of those:

public struct ProjectTaskDateTimeStamp
{
    Dictionary<TimestampType, DateTime> Times = new Dictionary<TimestampType, DateTime>();
}

There can be zero or one times for every timestamp type, which is analogous to your version with nullables.


If, for any reason, the above suggestion doesn't work for you:

Should I make this a class instead and why?

Yes:

  • A large struct is likely to degrade performance, because copying it around can involve multiple instructions. There are specialized instructions that are optimized for this, but they are not always emitted by the JIT.
  • C# semantics make handling mutable structs a bit tricky. As it stands right now, you haven't written it in a way that suggests it is immutable. You can make it immutable by turning the fields into readonly properties (properties with a get accessor only).
  • The memory layout of a nullable structure is just like that of the non-nullable version plus a boolean indicating whether there is a valid value. Compared to a structure that contains only non-nullable fields, a structure that contains only the corresponding nullable versions of the types will have an additional boolean in its memory layout for each of its nullable fields.

This is part of the declaration of Nullable<T>:

public struct Nullable<T> where T : struct
{
    private bool hasValue; 
    internal T value;
    ...
}

Don't be fooled by the fact that you can assign null to a nullable variable -- that's just C# syntactic sugar for calling its default constructor (which sets hasValue to false).

Community
  • 1
  • 1
Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • This (an enum plus a dictionary) was the first idea to come into my mind when I started thinking on what would be a better replacement for just a number of fields in the class itself, but it still left a sense of a "quick-and-dirty" solution, of semantic imperfection. Now as someone else is suggesting this, however, I am re-evaluating this and like it much better already, perhaps I will go this way, if another issue won't win: there is a reason (also not really serious so far, perhaps I will eliminate it) discouraging me from using collections among the class members. – Ivan Mar 12 '17 at 18:33
  • "A large struct is likely to degrade performance, because copying it around can involve multiple instructions" - I am actually curious about (this was the initial idea of the question) if is it going to be copied around although stored in a nullable variable and containing nullable variables (only nullable, perhaps) - aren't all nullable variables references? – Ivan Mar 12 '17 at 18:36
  • 1
    @Ivan `Nullable` is implemented as a struct containing a `bool` and a `T`. Of course, you can roll your own `Option` or something that does the same job but is a class instead. – Theodoros Chatzigiannakis Mar 12 '17 at 18:38
  • "As it stands right now, you haven't written it in a way that suggests it is immutable" - This sounds very interesting for me too, would you be so kind to explain? I am a huge fan of functional programming and immutable types so I am really curious about how can I define a C# type a way "suggesting it is immutable"? – Ivan Mar 12 '17 at 18:38
  • Please add what you have written about `Nullable` in the answer body and emphasise on it a way, this addition will make it a perfect answer to my question and I will be glad to approve it. Thank you very much, @theodoros-chatzigiannakis – Ivan Mar 12 '17 at 18:40