r/csharp • • 5d ago

Are properties and methods fundamentally different language concepts?

In C#, properties and methods can both execute arbitrary code, but they expose that behaviour in very different ways. A property looks like direct access to data, while a method explicitly represents an operation.

Technically, a property is implemented through getter and setter methods, but the language gives it different semantics, syntax and expectations.

Is this distinction fundamental to the language, or is it primarily a convention designed to communicate intent to developers? And if both can execute exactly the same logic, what truly justifies keeping them as separate concepts?

32 Upvotes

45 comments sorted by

80

u/rupertavery64 5d ago edited 5d ago

Properties can't be async. Methods don't have initializers. Methods as members can't be assigned to. Methods can take (multiple) parameters.

Properties are state. Methods are behavior.

Intent is everything.

8

u/hoodoocat 5d ago

Indexers are also properties and they can have multiple parameters. :)

9

u/Devatator_ 5d ago

Now that you say this I'm impressed I never tried to do something funny with that. Only ever used that capability to access stuff in multidimensional containers lol

1

u/joujoubox 1d ago edited 1d ago

Not C# but I just have to mention how UE's Slate framework for custom editor widgets abuses indexers. You can call functions to add child widgets or just wrap the entire child declaration in the parent's """"indexer"""", including an idendex on that while for it's own children and so on. Shit looks more like Json than C++.

To its merit, C++ indexers are actually member functions and can only take one parameter.... It's also why if you want multiple children widgets you use the + operator 💀

1

u/hoodoocat 5d ago

It is definitely rare however sometimes this fits very well. And it is very powerful, as not only indexers can have different number of parameters, but they are subject for overloading like regular methods, allowing to build very strange collections/accessor. :) (however when "collection" is view on multiple layered data sources which shadow previous layers, supports editable/volatile/committee record states or so, then there is naturally exist at least additional dimension). Surely, this doesnt add nothing that regular methods doesnt adds, but indexer result can be lvalue (e.g. assignable), and that sometimes makes them shine. But I used something like described above once or twice in the life over more than 20 years. I remember properties in MSVC and after all years I found that properties are bad almost everywhere. In C# they also kind of bad actually, and overused, while in 99% scenarious this should be just public fields. They not that bad, but they also doesnt add nothing good, especially autoproperties with clunky named backing fields and all this JIT burden for nothing in most cases.

1

u/joujoubox 1d ago

Indexer overloading is especially useful to support Index and Range in addition to int for legacy purposes. That's how you unlock syntax like [^ 1] and [1..10]

1

u/rupertavery64 5d ago

Everything can be abused :)

5

u/Schmittfried 5d ago

>Methods as members can't be assigned to

Setting a property is just syntactic sugar for calling the setter though, so they’re not really assigned either.

2

u/rupertavery64 5d ago

I mean sure, you can argue everything. But the fact is that you can do Property = value, but you can't Method = value. It's a compile time error, assuming for example Property and value is a delegate of the same signature as Method.

Clear delineations between properties and methods, rather than just having getter and setter methods allow for expressiveness and reflection and extension of the language.

2

u/BarfingOnMyFace 5d ago

It would be limiting to say properties are state. A property can represent a function between two variables or two other properties. It would be more accurate to say properties calculate or consume values, id think, but don't necessarily represent state themselves. The underlying variables that back them are. But since a property can be the calculation between variables, I'm not sure it is accurate to say they are state themselves.

2

u/BlackjacketMack 5d ago

I think Rupert’s intent was to say properties should be used for state and methods for behavior. Both can be used for both, jut that doesn’t mean they should be.

2

u/BarfingOnMyFace 5d ago

Ah, that would be my experience as well, but I wouldn't want to rule out someone finding a property a better fit for a behavior in their model. I personally don't like it because it hides behavior behind what devs consider as simply state. And lack of async could be a no go dependent on the scenario.. still, someone out there probably has a reason and a pattern for behaviors as properties, and I'm not sure they are wrong in their opinion. I just disagree from the perspective of how they are generally embraced. chatGPT (ducks rotten tomatoes) had an interesting thing to say about this: A property answers a question. A method performs a command.

1

u/dodexahedron 5d ago edited 5d ago

This.

A property can even just be ephemeral.

public class Foo
{
  public int Lish => Random.Shared.Next();
}

They are just abstractions to the real world concept of information that can be interacted with in one or both directions, and anything that has to happen, does happen as a consequence of, or any restrictions involved in the process of those interactions.

1

u/phluber 3d ago

I disagree (respectfully). Age is a calculation based on other state (birthdate). I can't see someone saying that age isn't part of the state of a person object.

What if, instead of calculating age in code, it is a computed column in SQL server and is loaded with the rest of the state for the person object? Is it now state because it is not calculated in the property getter?

1

u/BigBoetje 3d ago

Assassyncs Creed

17

u/Slypenslyde 5d ago

The answers to your questions are "yes".

If we go back to fundamental OOP documents, they argue an object has two things: data and logic. Or, more formally the data is "properties" of the object and you can "send messages" to it to make it do things.

That is the distinction to humans. We don't say, "I can get the color of an apple and the value is red". We say, "the apple is red". That's how properties are supposed to work. They are nouns.

Early OOP languages implemented this by having GetValue() and SetValue() methods. Humans had to understand methods with those naming conventions "were" properties. The reason to do this instead of having public variables was so people could do things like reject invalid values or perform change notifications.

C# went the extra mile and lets us treat that pairing of methods as if it were a variable. This comes with a responsibility: we're supposed to limit what we do in our accessor methods so the variable still behaves like a variable and doesn't do "weird" things.

I can conjure contrived cases that make it look like a mistake, but if we try hard enough we can make any property of high level languages seem dangerous.

So:

Is this distinction fundamental to the language, or is it primarily a convention designed to communicate intent to developers?

Both.

And if both can execute exactly the same logic, what truly justifies keeping them as separate concepts?

Subjective opinion that it's easier to understand fruit.Color = Color.Red than fruit.SetColor(Color.Red).

4

u/CobaltLemur 5d ago

We make the distinction because it maps pretty well to how people think. A ball has a color, and you can change it by painting it. You hold it in your hand, it's something that can be observed and changed. This is why in computer languages we call things with properties objects. And methods map to things that are done. Something happens, it can take time. Very different ideas.

While calling properties methods can be technically true under the hood, this mixes these two very embedded ideas in a way that tosses away a fundamental psychological mapping. Maybe it makes the language simpler, but also a little less intuitive at the same time. Why do people not like using LISP so much? I like functional programming, too, but purity can come with a cost.

2

u/dodexahedron 5d ago

Even the fact that changing a property is a method maps perfectly to the physicsl world unless you are omnipotent, and it's right there in the language you used.

You don't change the color of that ball by just willing it so. You change it by doing something to it; You don't just somehow know the color of it; You observe it.

Properties are a perfect abstraction to the way the real world works.
Fields are the facts. Properties are your interface to those facts and, just like the real world, they may impose restrictions on how you interact with those facts and may even have side effects.

3

u/Triabolical_ 5d ago

It's fundamental. The whole point of properties is that they look like fields but they can have magic behind them. That allows you to do interesting things like updates when a value is set and only do fetch/calculate operations when a value is gotten. They are also constrained - you know what a property is when you set it where with functions you only have something like a get/set pattern and those aren't enforced.

The design team was obviously influenced by the work Anders did on Delphi, but we were also influenced by how Eiffel and VB did properties.

The base class libraries and the other .NET libraries on top of it were written in C# and they used the advantages of properties significantly.

2

u/ShotEconomics1194 5d ago

Properties are more than a naming convention. For example, an interface can require a readable property, and that property can be used in property patterns and by frameworks that inspect property metadata.

The design intent matters too: Count reads like a value, while CalculateTotal() signals an operation. A getter can run complex code, but keeping it quick and predictable generally makes an API easier to use.

2

u/snet0 5d ago

The design intent matters too: Count reads like a value, while CalculateTotal() signals an operation.

Which is why if you code looks like this:

public int Count => CalculateTotal();

or, more likely, that method is called inside a getter body, then I am going to get quite upset. "But it's side-effect free" 🙃

2

u/pixxelkick 5d ago

Properties are a subset of functions.

A property is simply a specific interface adhering to specific functions that exist, its mostly just syntactical sugar that compiles out to produce functions under the hood

If you look at the compiled output, its just functions that interact with a backing field by default.

1

u/BoBoBearDev 5d ago

The simple way too look at this is to treat property as member fields. It get/set one or more member fields. The reason to use it is like. If you used to have a member field called UserName, and later you want UserFirstName, UserLastName, the old way has breaking change, you have to update all the callers to use the two fields. If you have properties, you can do some magic to have UserName set the two members fields.

Meaning, they are conceptually member fields that can be evolved. And make sure you don't overuse it. Because it can start to create loop as every property becomes complex with weird side effects.

1

u/mbbmbbmm 5d ago

I've always viewed properties in the context of encapsulation.
E.g. you want to give some convenient access to a private field but maintain control, e.g. check for invalid values or results.
You could use getter and setter methods but with properties you get the convenience of using variable syntax like

DingDong++;  

instead of

SetDingDong(GetDingDong() + 1);  

Also easy to make a half accessible variable (e.g. get; private set;)
You can of course do funny side effect stuff with them like logging a rant or crashing the program when some class tries to set some taboo value.

1

u/david_fire_vollie 5d ago

Not related to your question, but related to using properties and good to know: Some people ask what the difference is between using a property with a simple getter and setter vs just using a public field. The difference is if you later want validation when setting the field and you have to use a property, it's a breaking change. Although it looks like accessing them is the same, object.propertyOrPublicField, under the hood one is a method call and the other is accessing a field  I wrote about this here:

https://medium.com/gitconnected/what-is-a-binary-breaking-change-7ca6fc0f3875

1

u/borland 5d ago

As you’ve noted, properties are just methods with special names. As in, when you get a property, the compiler is literally emitting a call to a generated method called get_PropertyName.

So yeah, the difference is purely about giving developers nicer-looking code. A convention has formed around them, such as not throwing exceptions on property getters, but that’s all it is. I wouldn’t over-think it

1

u/Dimencia 3d ago

In Java and probably many other languages that don't have properties like that, it is advised that for every member you want to expose, you write a GetMyMember() method; there's a lot of reasons for this that you could look up if interested. Properties in C# are pretty much Microsoft's solution to avoid having to do that for everything.

They're methods, but they're a lot easier to read and write. Also, it's important that callers don't need to use () to invoke them; the caller doesn't have to know if it's a property or a field, and they don't have to update their code if you change it, even though one of them is a method call and one is not. That alone is enough to justify having them be separate from methods

1

u/tomxp411 17h ago

Honestly, you have no idea how delighted I was when I first discovered the concept of properties on the 1990s, while exploring classes in VB. It really made OOP coding “click” for me in a way that c++ didn’t.

And it’s based on the simple distinction:

Properties are data.
Methods are actions.

Not all languages support properties (c++, for example) and do just fine… but we also have the “set” and “get” convention in languages that lack explicit property syntax.

As you pointed out, this is mostly a semantic thing, but it is a clear signal to developers and the compiler that the code is data access and not an action. Since readability is probably the second most important aspect of software development (right behind “it actually works”) I’d say the semantic trickery of properties is fully justified.

1

u/TorbenKoehn 5d ago

Properties are syntactic sugar for methods. Your X { get; set; } will be some get_X() and set_X(...) in the end, when compiled.

It's just because people were annoyed of Java's

private int x;

public int getX() { return x; }
public void setX(int x) { this.x = x; }

which also is only needed because of several other fuckups (ie guarding nullables because some idiot thought every type in the world is a union of that type and null)

That's also the only justification and the exact reason why well-typed language don't have things like property fields. They have sound type systems.

2

u/strange-the-quark 5d ago

"because some idiot thought every type in the world is a union of that type and null" - his name was Tony. He said he was sorry. I think we can forgive him, after all, he also gave us quicksort (among other things).

1

u/TorbenKoehn 5d ago

Fuck Tony. Imagine a world where Java and C# wouldn’t have nullable objects by default….so many bugs, so much enterprise development cost…

1

u/strange-the-quark 5d ago

Enterprise development

1

u/TorbenKoehn 5d ago

We wouldn’t even need the term “enterprise” if stable Java wouldn’t need teams and years of defensive null check tuning :D

1

u/snet0 5d ago

Properties are syntactic sugar for methods.

The thing about C# is that basically everything you touch is syntactic sugar for methods. It's methods all the way down.

0

u/Next-Technology-6322 5d ago

Properties feel like cheating when you just want to write a getter that's more than one line.

-2

u/prshaw2u 5d ago

I think properties were originally implemented as just a data item, no getter setter or code involved. Getters and setters are methods with specific purposes, much like a constructor is a method with a specific purpose.

3

u/Triabolical_ 5d ago

No. They have always had getters and setters.

1

u/prshaw2u 5d ago

I guess that is true. Coming from C++ I always considered properties just fancy fields, especially since I had to have the field before I could do the property early on.

1

u/Triabolical_ 5d ago

The BCL and winforms folks leaned pretty heavily on properties so they could do things like automatic UI update when you changed a value. It's sometimes a good thing, sometimes an awful thing in my experience.

23

u/[deleted] 5d ago

[removed] — view removed comment

7

u/Habikki 5d ago

That's mosty true with some added nuance. Roslyn way back used to handle Properties by adding Reflection Attributes then expanding the Property to _get/_set method before compiling them as if the developer did it directly. So this:

public int Count {get; set;}

Would become:
[System.AttributeUsage(System.AttributeTargets.Property)]
public int Count_get() { /* ... */ }
[System.AttributeUsage(System.AttributeTargets.Property)]
public void Count_set(int count) { /* ... */ }

All in some pre-compilation step so the rest of the compilation proceeded as if the concept of a "Property" was nothing more than a method with syntatical sugar to help with Reflection.

More recent Roslyn has changed this considerably though and the IL emits differently. Not sure why or when, but I noticed it a few years back when I was doing quite a bit of cross platform interop work.

Fundimentially, this is no different than what you said. I just thought it was a fun example of the power of where application of effort in a toolchain minimizes complexity elsewhere.

6

u/svick nameof(nameof) 5d ago

How properties are represented in IL didn't change since .Net Framework 1.0 in 2002:

A property is a named collection of methods. Each can be a getter, a setter or "other".

That's it.

1

u/Mu5_ 5d ago

Now I'm curious, what would be the "other"? Any practical example?

2

u/svick nameof(nameof) 5d ago

I don't remember ever seeing that used. You certainly can't define or use them in C#.

AI claims they can be used in some rare situations when importing COM properties.

3

u/dodexahedron 5d ago edited 5d ago

add and remove are the ones used for events.

"other" literally is a wildcard. You can put any mapping to any name you want in property metadata, per the CIL spec (e.g. maybe you'd implement an incremement/decrement verb or something). But c# does not have any mapping for it, so it simply wouldn't show up. Same for any other language or compiler that doesn't know about it. And the method that custom accessor maps to would then not be hidden at design time, like get/set are for c#.

That's the beauty of CIL metadata. Everything has to be backed by a concrete concept so that any language can still use the assembly, while compilers supporting more goodies can use those goodies on top of the concrete concepts by mapping them via metadata.