DEV Community

No Sacred Cows: I, Interface

Sam Ferree on February 16, 2022

The Argument Why should we prefix the names of interfaces with I in C#? Here is the full answer given from Microsoft's documentation on ...
Collapse
 
jayjeckel profile image
Jay Jeckel

I think it makes more sense when combined with the convention of prefixing abstract classes with A. Then the differences of IThing, AThing, and Thing can be made apparent with a single letter. Incorporate an E prefix for enums and it becomes a bit more consistent than the lone cargo cult ritual of interfaces have to start with I. Sure, the convention does have a touch of Systems Hungarian to it, but in my experience it can be a useful way to name things.

As for why classes and structs don't get prefixes, as I was taught back in the days of rampant Hungarian notation, it's because they can be instanced and the prefixes are to differentiate the instantiable types from the non-instantiable types

Collapse
 
sam_ferree profile image
Sam Ferree

I'm curious as to the use case for needing to know whether a type is concrete or abstract just by looking at it?

Even if most modern editors couldn't give you this information right away, when would you need to create an instance of a type you know nothing about? when could you hope to do so correctly?

Collapse
 
jayjeckel profile image
Jay Jeckel

It isn't about readability at write-time, it's about readability at read-time. Anything that helps me understand the design of the system when I'm reading through the code is useful.

Take your example:

public class SqlBookRepository : BookWriter, BookReader { ... }
Enter fullscreen mode Exit fullscreen mode

That line of code tells me there are two types being used to derive a third type. Is the derived type based on a partial implementation (ie abstract class) and a contract (ie an interface) or is it based on two contracts? Can't tell here, so I'm going to have to dig further into the code to find out. However, a couple additional characters would answer the question without further digging. Is such information useful in toy examples like those in your article, arguably not really. Is it useful when digging through a project with hundreds of files and tens of thousands of lines of code? Yes, yes it is.

If all your doing is writing code, then I can understand finding such prefixes less than useful, but if you spend a major portion of life digging through other's code, then these little bits of context help.

And ultimately, that's the point, providing context about the purpose of a type. The I isn't a Systems Hungarian notation saying the type is implemented as an interface, it's an Apps Hungarian notation saying the type's purpose is as a contract for the api of the derived type.

Thread Thread
 
sam_ferree profile image
Sam Ferree • Edited

Note that your original point was about knowing whether or not you could instantiate something, which is done while writing code, and now you've seemed to switch gears saying it's about reading code.

I think IFF you're working in an editor where the color of abstract classes and interfaces are exactly the same, and where some information about the type doesn't come up when you hover over it and if you can't jump to the relevant file quickly with F12 or some similar keystrokes, THEN it could be useful to have that information.

But if you're working in an environment that limited, all of hungarian notation comes back on the table. What type is this variable? You can't know because you've told me your editor doesn't display that information and you can't jump to it quickly, so by your own argument it makes sense to preface strings with 'sz'

Is this a member variable? You can't know because you've told me your editor doesn't provide that information or a quick way to find it out. So we should provide that information be prefixing member variables with an '_'

So IFF that is your situation and you follow all of Hungarian notation rules, than I would say you're being consistent and writing code for good readability, but if not, then it sounds like cargo cult programming to me.

Thread Thread
 
jayjeckel profile image
Jay Jeckel

Note that your original point was about knowing whether or not you could instantiate something, which is done while writing code, and now you've seemed to switch gears saying it's about reading code.

Ah, I see the confusion. I wasn't suggesting that knowing what is concrete is the purpose of the convention, merely relating that, as I heard it back in the day, instantiable classes were considered the default and that is why non-concrete things get prefixes and instantiable stuff doesn't.

If there is a purpose to it, then that is to tell the coder what the job of the types is. No prefix, the types job is to be instantiated; I prefix, the types job is as a contract; A prefix, the job is as a base partial implementation; etc.

I think IFF you're working in an editor where the color of abstract classes and interfaces are exactly the same, and where some information about the type doesn't come up when you hover over it and if you can't jump to the relevant file quickly with F12 or some similar keystrokes, THEN it could be useful to have that information.

Maybe I'm getting old, but I don't find editor features to be a compelling argument for or against naming conventions. Others' experiene may be different, but I still read a good amount of code daily outside IDEs and the readablity of the code shouldn't be downgrade because it isn't be read in an editor.

But if you're working in an environment that limited, all of hungarian notation comes back on the table. What type is this variable? You can't know because you've told me your editor doesn't display that information and you can't jump to it quickly, so by your own argument it makes sense to preface strings with 'sz'

That's what I was getting at in the last post. The I prefix isn't Systems Hungarian telling you the type is implemented as a interface construct, it is Application Hungarian telling you the type is an API contract. For example, IEntity would be equivalent to EntityContract.

As another example, I don't need to prefix strings with s or other such, because their underlying type isn't what is important, their purpose is important, so their name would have DisplayText, FirstName, or some other descriptive name to make that clear.

Is this a member variable? You can't know because you've told me your editor doesn't provide that information or a quick way to find it out. So we should provide that information be prefixing member variables with an '_'

Yep, in my set of naming conventions, all private member variables are prefixed with _. And at this point it probably won't surprise you to find out that I also enforce the use of this/self scoping when calling member fields, methods, and properties.

So IFF that is your situation and you follow all of Hungarian notation rules, than I would say you're being consistent and writing code for good readability, but if not, then it sounds like cargo cult programming to me.

Yes, I religiously follow very consistent naming conventions and often reevaluate them for the dangers of cargo coding, but these have proved useful to me time and again.

Collapse
 
miketalbot profile image
Mike Talbot ⭐

Not that I totally disagree with the point you make about clarity, but I've always considered specially naming interfaces and abstract classes like this because you cannot create them. I can do new Dictionary but I immediately know I have to look for something to create or be an implementation if it starts with an "I" or an "A"

Thread Thread
 
sam_ferree profile image
Sam Ferree

I think that information is present, but insufficient to determine how you can obtain an instance of a given type.

A class might have a private constructor. In this case an S prefix to signal a struct actually would seem to be useful because it would tell you there has to be a public parameter-less constructor.

But that's not always true either. Consider the Guid type. new Guid() is almost never correct, and what you actually want is Guid.NewGuid().

If IEnumerable were just named Enumerable, would you just new them up? The kind of enumerable you need often depends on the situation. Creating a range happens under different circumstances than creating a List. Knowing that you can't call new IEnumerable is insufficient to tell you how to actually get one.

My point is that there's many things you need to know when trying to instantiate a given type. If you know so little about a type that you aren't sure if it's an interface or a class, then I wonder how you could know how to correctly instantiate it, or even why you need to. And all of this Even If this information wasn't quickly available to us in most modern editors.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Many holes in this. It was an interesting read for sure, though, so thumbs up overall.

Without the I how will we know which one is the base type and which one is the interface?

Your answer is "the compiler/language server". Ok.

// Which is which, in this code written in a comment in Markdown where there is no
// compiler or language server?
public class Lion : Animal, Biter, Carnivore
{
    ...
}
Enter fullscreen mode Exit fullscreen mode

See?

There are many good reasons to do this, and nearly all of them go away if our interface has only one implementation.

Even with just one implementation, interfaces are key to unit testing.

What would be useful to see is a descriptive name of how, such as SqlBookRepository, or InMemoryBookRepository. In this, far more clear, example we no longer need to preface our interface with I. The interface is BookRepository and we have two implementations, one that reads and writes books from a SQL database, and one that keeps them in memory.

This is not sufficient. I can have IBookRepository, then provide a base abstract class BookRepository. Now the "I" is useful again.

Collapse
 
_genjudev profile image
Larson
  • They create a consistent look to the code, so that readers can focus on content, not layout.

Look at my name and tell me what I'm. That is also how you can structure projects. When looking at the filename and folder in context you should already know what this is.

You see IBookRepository and knows what that is. Thats the whole reason. Analyzing the layout distracts from programming. When working in multiple projects it's really helpful not to think a second about what something is.

Collapse
 
sam_ferree profile image
Sam Ferree

When you say "what this is" do you mean you should be able determine domain specific information about what's in the file? If so I agree.

If you're saying I need to know whether the file contains an interfaces or some other type, then I'm not really sure you've provided anything sufficient to convince me why. If I see ScheduleWriter and ScheduleReader I don't need to spend any more time than I do when I see IScheduleRepository. I will either need to examine those files or not based on whether or not I need to persist Schedules.

If I don't need to persist Schedules, I can ignore ScheduleWriter and ScheduleReader as easily as I can ignore IScheduleRepository.

If I do need to persist Schedules, then I need to look at those files to see what the API is.

Collapse
 
stphnwlsh profile image
Stephen Walsh

Love this! Have moved away from I interfaces in a couple of projects I've worked on. It forces you to be mindful of naming.

Had a vehicle and vessel concrete types and the team settled on carrier as the interface. It was at the very least a fun discussion