So, given a frozen dataclass "C" with field names in "field_names", I propose changing __setattr__ to be:
def __setattr__(self, name, value):
if type(self) is C or name in field_names:
raise FrozenInstanceError(f'cannot assign to field {name!r}')
super(cls, self).__setattr__(name, value)
In the current 3.7.0a2 implementation of frozen dataclasses, __setattr__ always raises. The change is the test and then call to super().__setattr__ if it's a derived class. The result is an exception if either self is an instance of C, or if self is an instance of a derived class, but the attribute being set is a field of C.
So going back to original questions above, my suggestions are:
1. What happens when a frozen dataclass inherits from a non-frozen dataclass? The result is a frozen dataclass, and all fields are non-writable. No non-fields can be added. This is a reversion to the 3.7.0a1 behavior.
2. What happens when a non-frozen dataclass inherits from a frozen dataclass? The result is a frozen dataclass, and all fields are non-writable. No non-fields can be added. This is a reversion to the 3.7.0a1 behavior. I'd also be okay with this case being an error, and you'd have to explicitly mark the derived class as frozen. This is the 3.7.0a2 behavior.
3. What happens when a non-dataclass inherits from a frozen dataclass? The fields that are in the dataclass are non-writable, but new non-field attributes can be added. This is new behavior.
4. Can new non-field attributes be created for frozen dataclasses? No. This is existing behavior.
I'm hoping this change isn't so large that we can't get it in to 3.7.0a3 next month.