Inheritance and Polymorphism: Every time I try to get out, they pull me back in…

hurlbert
3 min readJan 8, 2023

--

The title (scarface) is a reference to the tragedy of mismanagement that has been inheritance and OOP in general. This is all a bit of a hot-take, but in the context of our previous conversations.

As you know, I’m not a fan of inheritance because I feel like the hierarchies are unmaintainable. Don’t get me wrong. I use it and I’m a quality craftsmen of oop code. But rather than becoming mired in the OOP landscape, it’s better to become embedded in the functional-programming landscape.

But there are absolutely no absolutes and some degree of flexibility is probably best. It’s with great interest that I did my strongest eye-roll and kept reading this post about how to use C# records.

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records

Take a look at the sample code:

public abstract record DegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords);

public sealed record HeatingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean < BaseTemperature).Sum(s => BaseTemperature - s.Mean);
}

public sealed record CoolingDegreeDays(double BaseTemperature, IEnumerable<DailyTemperature> TempRecords)
: DegreeDays(BaseTemperature, TempRecords)
{
public double DegreeDays => TempRecords.Where(s => s.Mean > BaseTemperature).Sum(s => s.Mean - BaseTemperature);
}

First of all the property “DegreeDays” has the same name as the abstract record — confusing. Second of all, the property “DegreeDays” has an implied getter that returns the results of the member body expression. This is genius on several levels because it essentially turns the class into a method with properties. This is true because both HeatingDegreeDays and CoolingDegreeDays are sealed, but also because records are not as malleable as classes.

A “method with properties” is not quite right. It’s more like a cluster of properties, some of which determine their value by returning the results of a method. Let that sink in.

Anyway, the point of this short email is that this turns the paradigm on its head in regards to the hierarchy and management of subclasses. Why? Well, this is the mind blowing part and we have to think back to the first principles of C# (and interface based OOP languages in general).

Interfaces define types. Classes implement behavior and have a types. With records, we get a way to stay true to types, but sneak in a bit of behavior.

I’m not saying this is a good or a bad thing. For that, I need more time to think about it. This message is just pointing that out. But before we finish, let’s look at this all with an eye toward immutable records.

Non-destructive mutation:

The synthesized members in a positional record class don’t modify the state of the record. The goal is that you can more easily create immutable records. Remember that you declare a readonly record struct to create an immutable record struct. Look again at the preceding declarations for HeatingDegreeDays and CoolingDegreeDays. The members added perform computations on the values for the record, but don’t mutate state. Positional records make it easier for you to create immutable reference types.

This directly addresses what type of behavior we want to be adding — it should be computations, not mutations. This keeps us on track for functional programming.

And for those wishing to implement historical records ala “Immutable Architecture” the record type finally gives C# the “with” keyword so you can say, “create a new instance WITH the values from the old instance.” This is cloning without needing to bother cloning. Awesome. Why is that important? One of the reasons is that it leaves the optimization in the hands of the language. If you’ve ever chunked together some crappy cloning code you’ll understand. “They” can do it way more efficiently than “we” can. People used to complain that LINQ was “going to be slow.” You don’t hear that as much because “they” have done an excellent job optimizing it so that “we” don’t have to.

Last, in case you haven’t figured it out yet this is Microsoft adding the positional-record-concept to C#. What other disruptive technology uses “positional-records?” That’s right gRPC and protobuf. It’s my belief that they are backing in (or at least moving f’ing slowly) toward gRPC compatibility at the language level. This will then enable almost trivial implementation of ServiceModelEx type libraries for gRPC. We are already seeing some signs of that with the introduction of these new functions: https://stackoverflow.com/questions/65123223/does-protobuf-net-support-c-sharp-9-positional-record-types

This is some wild evolution.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

No responses yet

Write a response