Concepts / Designing Classes with Fields

Designing Classes with Fields

Placing both inside one class means they travel together, so code that receives the class also receives the tag that says how to read the union.

  • Programming

Predicting What a Shared Storage Area Returns

Imagine a single storage area that a program can read in more than one way. You write a value into it while thinking of it as one kind of value, then later read it while thinking of it as a different kind. Before reading on, decide what you expect the second read to give you. This section is about exactly that situation, and about the design habit the source warns against when it happens.

What do you think happens?

If one storage area is written as one type and then read as another type, can the program rely on the second read being meaningful?

  • Yes, the value is always converted correctly

  • No, the second read reinterprets whatever was last stored and may not be meaningful

Reveal answer
Answer:

No, the second read reinterprets whatever was last stored and may not be meaningful.

The source describes a union as one storage area that holds a value which may be one of several types. The program then has to know which member is in use. Without that knowledge, reading a member other than the one last written gives meaningless data. The rest of this article explains why, and how the source's correction addresses it.

What a Union Is

Definition

A union is a user-defined type that lets one storage area hold a value that may be of one of several different types.

The key word is one. A union does not hold several values at once. It holds a single value, and that value can be interpreted as any of the member types the union declares. Because the union is so compact, it is tempting to declare one and use it directly, relying on your memory of what it currently holds. The source names that habit specifically.

Why the Naked Union Is a Problem

The word naked describes a union with nothing around it. The value is stored, but the program has no dedicated place that states what kind of value it is. Everything the program needs to know about the stored value has to be carried in the programmer's head or spread across scattered code. That is exactly what the source warns against.

Shared storage areaholds one stored valueMember read asintegerinterprets the stored valueMember read as floatinterprets the same storedvalueview as integerview as float
When every member of a union shares the same storage, what does reading one member return after another member was written?

In the diagram, both members are views onto the same storage area. Writing through one member and reading through the other does not give you a separate, correct copy of a value. The program must already know which member was written last. If it does not have that information recorded anywhere, the read is a guess.

Wrapping the Union with a Type Field

The source gives a specific correction. Wrap the union in a class, and include a type field alongside it. The union holds the data. The type field holds the information needed to interpret that data. Placing both inside one class means they travel together, so code that receives the class also receives the tag that says how to read the union.

Wrapping classtravels as one unitType fieldrecords which member is inuseUnionholds the dataPublic membersthe interface code usescontainscontainsexposes
How are the type field, the union, and the wrapping class's public members arranged, and which part is responsible for what?
PartResponsibility
UnionHolds the stored data in one storage area
Type fieldRecords which member is in use, so the reader does not have to rely on memory or assumption
Wrapping classKeeps the union and its type field together so they are passed around as one unit

The three parts of a safely wrapped union and what each one is responsible for

Key point

The type field is what makes the stored value interpretable without relying on memory. The source does not spell out further details of this field, so treat it as the recorded tag that the class provides alongside the union.

Naked Versus Wrapped Usage

The same union can be used in two ways. Used directly, it is naked: code that receives it must already know which member was last written. Used inside a tagged wrapper, the type field carries that knowledge with the data. The diagram below contrasts the two designs.

Bare unionMeaning kept inmemoryWrapping classType fieldUnionrelies oncontainscontains
What changes between using a naked union directly and using it inside a tagged wrapper class, and what is the recommended correction?
Worked example

Spotting and Correcting a Naked Union

A design declares a union that holds either an integer or a float. Functions receive the bare union and decide how to read it by remembering which member was last written. Identify the naked-union pattern and state the correction the source recommends.

  1. 1
    Find the storage

    The union is the only thing that holds the value. Nothing else in the design records which member is in use.

  2. 2
    Find the missing record

    The functions rely on memory or assumption to know the active member. That is the habit the source calls a naked union.

  3. 3
    Apply the correction

    Wrap the union in a class and add a type field beside it. The union holds the data and the type field records which member is in use.

  4. 4
    Check the result

    Code that receives the wrapping class now also receives the tag, so it no longer has to guess how to read the union.

Result

The bare union is naked. The source's correction is to wrap it in a class together with a type field, and to make that structure decided when the union is introduced rather than passing the bare union around.

Mistakes When Wrapping a Union

  • Common mistake

    Using a union directly because it is compact

    What it looks like

    A function receives the bare union and assumes it holds an integer because that is what was written last time.

    Why it fails

    Nothing in the design states which member is active, so the read depends on memory or assumption.

    Do this instead

    Wrap the union in a class together with a type field so the tag travels with the data.

  • Common mistake

    Keeping the type field separate from the union

    Why it fails

    If the tag and the union are passed separately, code can receive the data without the information needed to read it.

    Do this instead

    Place the union and the type field inside one class so they travel together.

  • Common mistake

    Deciding the wrapping structure late

    Why it fails

    Once the bare union has been passed around, the naked pattern has already spread through the code.

    Do this instead

    Decide on the wrapping structure when the union is introduced, rather than passing the bare union around.

Practice Spotting the Missing Tag

EASY

A colleague passes a bare union to several functions. Each function decides how to read the union by remembering which member was written last. Identify the naked-union pattern in this design and state the correction the source recommends.

Hints
  • Ask where the design records which member is in use. If the answer is only memory, the union is naked.
  • The source's correction has two parts: a wrapping class and a type field placed alongside the union.

Key Takeaways

  • A naked union is a union used on its own, with no dedicated record of which member holds the value, so the program relies on memory or scattered code.
  • A union is a user-defined type that lets one storage area hold a value that may be of one of several types.
  • The source's correction is to wrap the union in a class together with a type field that records which member is in use.
  • The wrapping structure should be decided when the union is introduced, rather than passing the bare union around.

Related concepts

More concepts starting with D