Why are private fields private to the type, not the instance?
I think one reason it works this way is because access modifiers work at compile time. As such, determining whether or not a given object is also the current object isn't easy to do. For example, consider this code:
public class Foo
{
private int bar;
public void Baz(Foo other)
{
other.bar = 2;
}
public void Boo()
{
Baz(this);
}
}
Can the compiler necessarily figure out that other
is actually this
? Not in all cases. One could argue that this just shouldn't compile then, but that means we have a code path where a private instance member of the correct instance isn't accessible, which I think is even worse.
Only requiring type-level rather than object-level visibility ensures that the problem is tractable, as well as making a situation that seems like it should work actually work.
EDIT: Danilel Hilgarth's point that this reasoning is backwards does have merit. Language designers can create the language they want, and compiler writers must conform to it. That being said, language designers do have some incentive to make it easier for compiler writers to do their job. (Though in this case, it's easy enough to argue that private members could then only be accessed via this
(either implicitly or explicitly)).
However, I believe that makes the issue more confusing than it needs to be. Most users (myself included) would find it unneccessarily limiting if the above code didn't work: after all, that's my data I'm trying to access! Why should I have to go through this
?
In short, I think I may have overstated the case for it being "difficult" for the compiler. What I really meant to get across is that above situation seems like one that the designers would like to have work.
Why can an instance of a class access private fields of another instance of its own type?
First you have to ask "why have private fields at all?"
Private fields are primarily for encapsulation: a consumer of a class shouldn't have to know the internals of that class' implementation, and in fact those internals should be actively hidden from the consumer. Otherwise, if a user relied on those internals, then the implementer would be forced to support them or break backwards compatibility. In other words, it protects both the user and designer of the class:
- users are protected from implementation changes breaking their code
- the designer is protected from having to keep implementation details features unchanged forever
But a class doesn't need to be protected from itself; it doesn't need to worry about the case where one bit of its code changes, but another bit (that uses the first bit) can't change. Backwards compatibility is not a concern, because the class is developed and deployed as a single, atomic chunk of code. In other words, neither of the above protections are needed.
Since there's no need to protect the fields, and since it's often necessary to see them (for instance, to compare if two objects are equal), they're visible within the class.
In Java, why are the private data members accessible outside the class if written like this?
Because the method is in the same class, it can access private members of other instances. private
only means that only functions in the class can access it, with no restrictions on which object is doing the accessing.
What are the differences between the private keyword and private fields in TypeScript?
Private keyword
The private keyword in TypeScript is a compile time annotation. It tells the compiler that a property should only be accessible inside that class:
class PrivateKeywordClass {
private value = 1;
}
const obj = new PrivateKeywordClass();
obj.value // compiler error: Property 'value' is private and only accessible within class 'PrivateKeywordClass'.
However compile time checking can be easily bypassed, for example by casting away the type information:
const obj = new PrivateKeywordClass();
(obj as any).value // no compile error
The private
keyword is also not enforced at runtime
Emitted JavaScript
When compiling TypeScript to JavaScript, the private
keyword is simply removed:
class PrivateKeywordClass {
private value = 1;
}
Becomes:
class PrivateKeywordClass {
constructor() {
this.value = 1;
}
}
From this, you can see why the private
keyword does not offer any runtime protection: in the generated JavaScript it's just a normal JavaScript property.
Private fields
Private fields ensure that properties are kept private at runtime:
class PrivateFieldClass {
#value = 1;
getValue() { return this.#value; }
}
const obj = new PrivateFieldClass();
// You can't access '#value' outside of class like this
obj.value === undefined // This is not the field you are looking for.
obj.getValue() === 1 // But the class itself can access the private field!
// Meanwhile, using a private field outside a class is a runtime syntax error:
obj.#value
// While trying to access the private fields of another class is
// a runtime type error:
class Other {
#value;
getValue(obj) {
return obj.#value // TypeError: Read of private field #value from an object which did not contain the field
}
}
new Other().getValue(new PrivateKeywordClass());
TypeScript will also output a compile time error if you try using a private field outside of a class:
Private fields originates from a TC-39 ECMAScript proposal and are part of the 2021 ECMAScript specification, which means that they can be used in both normal JavaScript and TypeScript.
Emitted JavaScript
If you use private fields in TypeScript and are targeting older versions of JavaScript for your output, such as es6
or es2018
, TypeScript will try to generate code that emulates the runtime behavior of private fields
class PrivateFieldClass {
constructor() {
_x.set(this, 1);
}
}
_x = new WeakMap();
If you are targeting esnext
, TypeScript will emit the private field:
class PrivateFieldClass {
constructor() {
this.#x = 1;
}
#x;
}
Which one should I use?
It depends on what you are trying to achieve.
The private
keyword is a fine default. It accomplishes what it was designed to accomplish and has been used successfully by TypeScript developers for years. And if you have an existing codebase, you do not need to switch all of your code to use private fields. This is especially true if you are not targeting esnext
, as the JS that TS emits for private fields may have a performance impact. Also keep in mind that private fields have other subtle but important differences from the private
keyword
However if you need to enforce runtime privateness or are outputting esnext
JavaScript, than you should use private fields.
Also keep in mind that organization/community conventions on using one or the other will also evolve as private fields become more widespread within the JavaScript/TypeScript ecosystems
Other differences of note
Private fields are not returned by
Object.getOwnPropertyNames
and similar methodsPrivate fields are not serialized by
JSON.stringify
There are importance edge cases around inheritance.
TypeScript for example forbids declaring a private property in a subclass with the same name as a private property in the superclass.
class Base {
private value = 1;
}
class Sub extends Base {
private value = 2; // Compile error:
}This is not true with private fields:
class Base {
#value = 1;
}
class Sub extends Base {
#value = 2; // Not an error
}
A
private
keyword private property without an initializer will not generate a property declaration in the emitted JavaScript:class PrivateKeywordClass {
private value?: string;
getValue() { return this.value; }
}Compiles to:
class PrivateKeywordClass {
getValue() { return this.value; }
}Whereas private fields always generate a property declaration:
class PrivateKeywordClass {
#value?: string;
getValue() { return this.#value; }
}Compiles to (when targetting
esnext
):class PrivateKeywordClass {
#value;
getValue() { return this.#value; }
}
Further reading:
- The future of the "private" keyword
- TypeScript PR that added private fields
Why I can not access private field of a base class when private variables can be accessed this way
If we can access the private variables of Class as mentioned then why a class which extends another class can not access private variables of base class?
Because the variable isn't declared in the program text of the derived class, which is how private access is defined for Java and C#. (The details around nested classes vary between Java and C#; if you want details for one language or the other, please be more specific in your question.)
I believe when code or classes will be compiled then all the methods, variables etc of base class will be added to derived class. Am I right on this?
They're not added to the class, no. They're inherited by the derived class, and any instance of the derived class will have all the fields that are inherited - but that's not the same as them behaving as if they were declared in the derived class.
Why doesn't YamlDotNet serialize private fields of the class?
The reason why YamlDotNet serializes only public properties by default is because doing otherwise would break encapsulation. Accessing private members would mean that the model would be unable to guarantee its invariants. If you compare with other libraries, such as Json.NET, you will notice that they use the same approach.
I don't think that this is a problem because you should not be (de)serializing your domain model directly. Doing so would constrain your domain model to your serialization schema, which in many cases will need to be different. That's the same problem as trying to map your domain model to a relational database.
Instead, you should define a serialization model and map between your domain model and that serialization model. In that case there's no need to serialize private fields.
That said, if you really want to serialize private fields, that's trivial to do. You need
register you own implementation of ITypeInspector
that returns private fields. You can base your implementation on ReadableFieldsTypeInspector
.
Access private field of a instance object
Privacy is not per instance - it's per class.
The class can access the private fields of all instances.
For example, the method equals( Object o )
can cast o (if appropriate) to the same type, and compare its private members with the object on which equals() was called.
Related Topics
How Much Memory Does a C#/.Net Object Use
Programmatically Set Browser Proxy Settings in C#
Determine What Control the Contextmenustrip Was Used On
Linq to SQL and a Running Total on Ordered Results
Retrieving the Calling Method Name from Within a Method
How to Convert Datatable to JSON String Using JSON.Net
Best Way to Display Decimal Without Trailing Zeroes
How to Post Data Using Httpclient
Differencebetween Getter-Only Auto Properties and Expression Body Properties
How to Obfuscate My C# Code, So It Can't Be Deobfuscated So Easily
How to Find All Implementations of an Interface
Why Does My C# Gzip Produce a Larger File Than Fiddler or PHP
Move Window When External Application's Window Moves
What's the Best Way of Accessing Field in the Enclosing Class from the Nested Class