Remix.run Logo
jnwatson 2 hours ago

You're holding it (Python) wrong. Python OO was a counter reaction to the bondage and discipline that languages like C++ had with private members and protected inheritance.

If you have members that users probably shouldn't touch, you prepend them with an underscore. This is just a hint; It doesn't actually change anything. We're all adults here and we know the consequences of reaching into implementation details.

ddavis 2 hours ago | parent | next [-]

I agreed with this 100% for a long time. Then I started working on a library at $WORK with dozens of downstream users abusing the hell out of my idiomatic underscore usage, especially in the context of lazy tests with folks writing endless mocks. When I’d “break” their test suite (blocking some time sensitive release) I’d get all kinds of shit. But _they_ were breaking the contract. Unfortunately I had little (if any) control on the path of application code making it to production (yeah yeah not great engineering org, but it’s the world I lived in). Strategies like this post would be helpful for said situations.

senkora an hour ago | parent | next [-]

There’s always the extra idiomatic __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED for coworkers that can’t take a hint.

https://github.com/reactjs/react.dev/issues/3896

jghn an hour ago | parent | prev [-]

Something similar happened to me. I told those groups to pound sand because they knew they were relying on something which they should not. Manager had my back, they whined a lot but they had to change and improve their processes.

sdeframond 2 hours ago | parent | prev | next [-]

> We're all adults here and we know the consequences of reaching into implementation details.

I wish you were right but, IMHE, it requires a lot of communication once teams grow and many team member do not fully understand the consequences of what they do. It is nice to have something that helps when reviewing code.

> If you have members that users probably shouldn't touch, you prepend them with an underscore

Well, this is precisely what TFA does. It prepends the constructor with an underscore.

masklinn 2 hours ago | parent | prev | next [-]

I think you missed the issue at hand:

> even if you keep all your fields private, the constructor is still, inherently, public.

ShippingOptions and the literals / enums are part of the public API, so the user would just be writing

    ShippingOptions(Carrier.USPS, Conveyance.Air)
with no hint that they're doing anything wrong.

Dataclasses do have a `kw_only` option, but I'm not sure how well underscore prefixes would be understood as private parameters / a private ctor, whereas wrapping a clearly "private" type should be clear to everybody.

Glyph is not entirely correct on the "any class" bit as you can always break the default init path:

  class ShippingOptions:
      _ship: Literal["fast", "normal", "slow"]
      __init__ = None


  def shipFast() -> ShippingOptions:
      opts = object.__new__(ShippingOptions)
      opts._ship = "fast"
      return opts
however that's a pretty ugly pattern, and unlike the one they propose I doubt tooling would understand it.
5691827 2 hours ago | parent | prev [-]

"Glyph" knows. He has been in the Python inner circle for decades back to when the circle promoted "spam and eggs" and "consenting adults".

Like the rest of that circle, he moves with the times, supports public shaming of Tim Peters and others and now promotes poorly implemented information hiding so Python ticks a few more boxes for the industry.

Information hiding in a language that allows changing the values of small integers at runtime via ctypes is doomed anyway. And there are plenty of better languages that do it out of the box and in a straightforward manner.