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 ...
For further actions, you may consider blocking this person and/or reporting abuse
I think it makes more sense when combined with the convention of prefixing abstract classes with
A
. Then the differences ofIThing
,AThing
, andThing
can be made apparent with a single letter. Incorporate anE
prefix for enums and it becomes a bit more consistent than the lone cargo cult ritual of interfaces have to start withI
. 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
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?
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:
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.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.
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.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.
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 ainterface
construct, it is Application Hungarian telling you the type is an API contract. For example,IEntity
would be equivalent toEntityContract
.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 haveDisplayText
,FirstName
, or some other descriptive name to make that clear.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 ofthis
/self
scoping when calling member fields, methods, and properties.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.
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"
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.
Many holes in this. It was an interesting read for sure, though, so thumbs up overall.
Your answer is "the compiler/language server". Ok.
See?
Even with just one implementation, interfaces are key to unit testing.
This is not sufficient. I can have
IBookRepository
, then provide a base abstract classBookRepository
. Now the "I" is useful again.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.
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.
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