Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Locking away backing fields from a property is not an unnecessary feature.



If somebody needs access to the backing field it's usually for a good reason. And if you restrict it, they'll just fork your code and overwrite whatever they need.

It should at most be a soft annotation to prevent it from getting auto-completed, not a restriction.


You're assuming a very simplistic model of API coupling, where there are only "applications" and "libraries that the application compiles into itself." But:

• There are also runtimes, installed separately from the application. You might be able to fork the JDK, but people want to run your Java application on their JRE, not yours.

• There are proprietary applications that nevertheless expose APIs to code against. A Photoshop plugin author can't fork Photoshop to expose fields of the plugin host.

• There is the OS itself. You can fork the Linux kernel (and gcc/clang) to expose some internal data your application needs as a system call — but unless you get all that code upstreamed, your application is now entirely non-portable, running only on your own servers at best.

• Most commonly of all, there are system libraries. You can certainly fork (and co-distribute / bake in) a library like libicu or libxml — but no major OS will be willing to ship your app or lib as a system package of its own, if it does that. They'll want your app/lib to depend on the existing packaged version of those libs.

None of this matters, of course, if you develop proprietary-service backend software for a living. You can maintain a menagerie of weird lib forks, shove all the build artifacts into a docker image, and it'll work for you. But much (I'd say the majority) of the world's programming is not in proprietary-service backends, and so needs to actually depend on code it doesn't control.


All very good arguments about not having private and protected.


> And if you restrict it, they'll just fork your code and overwrite whatever they need.

More power to them. They can take responsibility for that code and maintain it and I don't have to worry about breaking them when I release a new version. Everyone's happy.


I like Boost's approach[1] of using a separate namespace for these implementation-specific things, rather than visibility modifiers.

Then the internals are accessible if you need it for a temporary workaround or such, but it's also very obvious when you are accessing stuff you really shouldn't. And implementers are still free to rearrange the internals as they see fit.

[1]: Not saying Boost invented it, just where I saw it first.


Boost uses both. Implementation-private namespaces are a slightly different feature. They provide a way to share internal methods between classes within boost that must not be used by client code. That's a scoping feature that c++ doesn't have, but c# (for example) does.


and then they also own future responsibility for that change.


It's always app dev responsibility. They can't excuse a bug or lack of functionality with "that's what's in the lib".

I can't imagine somebody monkey patching exposing internals of a lib and blaming lib author for poor effects.


How are they to distinguish between what are internals and what is the public interface if the internals aren't locked behind something like 'private'? Naming convention? [0] Code comments, or other documentation? A thorough reading of the codebase?

[0] Good luck with enforcing the One True Naming Convention.


That's why I suggested it should be an annotation at most, so you can convey the intent without limiting the users.

It can still be using keywords like public, protected, private. Just make them non-binding. In similar manner how TypeScript types are non-binding. You can ignore them in any program that uses TS lib.


> ...so you can convey the intent without limiting the users. It can still be using keywords like public, protected, private. Just make them non-binding.

Yeah, the users aren't likely to be really limited these days.

1) A huge number of widely-used languages have reflection, so you can get at internal members if you really try.

2) For those languages that don't, just remove the keyword and recompile. Someone who's willing to take on the maintenance burden of directly using parts of the software marked by their author as "internal only do not use" is clearly willing to maintain such a minor fork.


And now they've introduced a tight coupling and some serious potential tech debt should the original ever change its internal workings.

Also, you seem to assume we're talking about open source here.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: