If someone encodes "Meter" and "Yard", your type system wouldn't provide any errors if a meter is used in a yard calculation or vice versa. If someone encodes "RGBColor" and "LinearRGBColor", both structs with 3 floats, your type system wouldn't provide any errors if a LinearRGB color is passed into an RGB calculation. You also wouldn't have any error if you accidentally passed a Vertex3 (again, struct of 3 floats) into your RGB calculation.

Also, preferred by who?

Preferred by me, I'm not trying to speak for anyone else. In fact I'd say it's a somewhat minority opinion.

When talking about types like `Meter` and `Yard` in a structural system, the "type" of the data is also data. In a nominal system that data is encoded in the type system, but that's not the only place it can be. For example, if I asked you how far the nearest gas station is, you wouldn't respond with "10", but rather "10 minutes", or "10 kilometres", etc. Both the value and unit of measurement are relevant data, and thus both of those would be part of the structural type as well.

   { unit: yard, value: 20 }
This is real, concrete data that you can see all at once. You can feed it into different functions, create aliases for it (unlike objects where you'd need to make snapshots or copies when they might change), compare it with other data to check equality, transmit it across networks, and work with it easily in other programming languages since they all understand basic types. When you stick with this kind of data, you can use general-purpose functions that work on any data rather than being locked into specific methods tied to particular types or interfaces - methods that won't exist when you move to different languages or systems.

In a nominal system you might end up with a generic Measurement<T> type that contains the unit inside, which can help with code reuse but it's not at the same level as pure data.

The issue with this is that you can make mistakes with the general-purposed functions.

a function `fn convertYardsToKm(value: i32): i32` doesn't fail when you give it a weight.

Whereas in Rust you'd write something like this:

    #[derive(Copy, Clone)]
    struct Yard(i32);

    #[derive(Copy, Clone)]
    struct Km(i32);

    #[derive(Copy, Clone)]
    struct Lbs(i32);

    #[derive(Copy, Clone)]
    struct Kg(i32);
and your functions becomes `fn convertYardsToKm(value: Yard): Km`

You can group them in an enum

    enum Measurement {
        Yard(Yard(i32)),
        Km(Km(i32)),
        Lbs(Lbs(i32)),
        Kg(Kg(i32)),
    }
(Note that it would be nice if we could refer to `Measurement::Yard` as a type vs have to add a distinct `Yard` type).

That way there is no confusion what you're putting in, and what type the output is, which has resulted in for example an emergency landing https://en.wikipedia.org/wiki/Gimli_Glider#Miscalculation_du... and loss of a Mars probe: https://en.wikipedia.org/wiki/Mars_Climate_Orbiter

There 100% are unit systems implemented with types. (One example: https://github.com/goldfirere/units/tree/master/units)

Structural types does not preclude having some names that prevent mix-ups. Haskell’s `data` keyword doesn’t let you confuse structurally-identical things.

> If someone encodes "RGBColor" and "LinearRGBColor", both structs with 3 floats, your type system wouldn't provide any errors if a LinearRGB color is passed into an RGB calculation.

It 100% would, unless you were silly enough to use a bare tuple to do it. Again, defining a type with `data` in Haskell wouldn’t get confused.

> Structural types does not preclude having some names that prevent mix-ups. Haskell’s `data` keyword doesn’t let you confuse structurally-identical things.

Haskell doesn't let you confuse structurally-indentical things because it is nominal, not structural.