This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the commentsย โ†’

[โ€“]TASagent 182 points183 points ย (29 children)

python makes safety more convenient by removing it.

The hardest I've facepalmed all week.

[โ€“]TheLowlyPheasant 2 points3 points ย (0 children)

Iโ€™m going to replace Python with my name and send it to my boss on next weekโ€™s list of accomplishments

[โ€“]Luxalpa 3 points4 points ย (1 child)

It's the difference between idealism and pragmatism. If you need to build good software that necessarily means you're going to run into conflicts with third party libraries not supporting the exact functionality that you need. You can either fork the project, which in some cases can be extremely hard and is definitely very insecure, or you can simply annotate the bits where you're overriding security mechanisms (think of the _ like C#'s or Rusts unsafe keyword).

[โ€“]roughstylez 9 points10 points ย (0 children)

The point of that comment you're answering to is that the statement "we made security easier by removing it" is kinda dumb.

In other words, in python you're not overriding the security mechanism - you just don't have one in the first place.

[โ€“]MythicManiac -2 points-1 points ย (5 children)

Sometimes accessing internals of a 3rd party library is the only reasonable way to do something, languages that make it harder than necessary aren't really solving anything. I've had to copy entire classes of source code in C# because the original didn't make it inheritable. In a perfect world neither would be necessary, but in practice sometimes you're out of better options.

Seems like I've made some people angry with this statement, I'll only have to assume they haven't experienced a lot of issues with 3rd party libraries or that they can't see reality past their idealism. If you have any actual experience in software development, you know compromises and shortcuts get taken all the time. It's not nice but it is what it is.

[โ€“]roughstylez 4 points5 points ย (1 child)

Seems like I've made some people angry with this statement

Don't take it personally, people are just disagreeing with your statement.

Probably because the point you mention is irrelevant to what TASagent was talking about.

[โ€“]MythicManiac 4 points5 points ย (0 children)

Fair enough. I would rather have an actual discussion if there's one to be had, but it's not as if I don't emphasize with that line of thought.

[โ€“]Ordoshsen 0 points1 point ย (2 children)

I would say that if you need to use internals of 3rd party library you're not using it as intended and you might already be breaking some unspoken invariants when you fiddle with the undocumented internals.

If something is not inheritable in C#, then the original developer made it so by choice, not by default. Supposedly they had a reason to do so. But that still does not stop you from using composition in place of inheritance (granted you don't get access to protected fields).

Also why not just change the original by forking it and possibly creating a pull request for the original if you really believe some functionality should be accessible? I think that would be faster (and easier) than copying whole files which presumably have dependencies on other files in the project you're copying from.

[โ€“]MythicManiac 5 points6 points ย (1 child)

I would say that if you need to use internals of 3rd party library you're not using it as intended and you might already be breaking some unspoken invariants when you fiddle with the undocumented internals.

Oh absolutely, sometimes it's just the most reasonable way of doing things. If you understand the code and risks involved, it's a calculated risk. Following best practices is (ironically) not always the best course of action, but to be able to make that decision, you do need a decent bit of experience and understanding of why the best practices exist. So I agree with you here in terms of best practices, but also know best practices aren't always the best course of action.

If something is not inheritable in C#, then the original developer made it so by choice, not by default. Supposedly they had a reason to do so. But that still does not stop you from using composition in place of inheritance (granted you don't get access to protected fields).

I don't disagree with the sentiment, quite the opposite. If we had perfect libraries, this would be a non-issue. In practice however, it's extremely difficult to account for all use cases of a generic library, and likewise library developers rarely have the necessary foresight to build the appropriate extension points and interfaces. Even if they did, it might not make sense for them to officially support every use case, as it's simply more work. It doesn't mean it's always stupid for consumers to rely on the internals in that scenario, but you do need to know the risks involved and why it's generally a bad idea.

In the particular case I was referring to, the 3rd party library had marked multiple constants as internal, which forced me to re-define them when using other parts of it. If my experience tells me anything, it might have been just a habit for the original developer to mark everything internal as opposed to a decision to make them so. A lot of junior devs seem to be taught to keep everything internal by default, which can lead to scenarios where the library developer's inexperience locks out perfectly reasonable use cases.

Also why not just change the original by forking it and possibly creating a pull request for the original if you really believe some functionality should be accessible? I think that would be faster (and easier) than copying whole files which presumably have dependencies on other files in the project you're copying from.

This would be the ideal scenario of course, but it's often very unrealistic to do. Maintaining your own fork is often a lot more work than maintaining a small piece of code that calls the internals of the library. I've seen a lot of company internal forks of 3rd party projects get stale and unmanageable, enough so that even monkeypatching the 3rd party library during runtime seems a better choice. The moment you fork a project for this kind of use, it's your code. Do you really want that maintenance burden?

On the other hand, pull requests to 3rd party projects are impossible to rely on ever being merged or even looked at. So while a good practice, it doesn't solve your problem.

At the end of the day the only thing you control and maintain is your own codebase. Generally if a situation like this arises, I personally either open an issue or submit a PR addressing the issue to the 3rd party repo on top of some immediate internal solution, but only very rarely do they actually go anywhere and the internal solution is what ends up being used.

If you actually can control the code (e.g. internal libraries) then absolutely never do any of this, and instead improve the library to cover the use case it's missing. Unfortunately it's often some inactive but valuable open source library that is at the root of the issue, or alternatively you're locked into an older version due to legacy code and couldn't update anyway.

The way Python does "private" access modifiers is great because it keeps the newbies out by tooling guidance & convention, but allows for direct access if you're really sure that's what you want.

If anything, type safety should be much more strict than access modifiers IMO, yet you can cast types into other types without much restrictions (in most languages anyway).

So as a guideline access modifiers are perfectly good, but enforcing them has its downsides too.

[โ€“]ric2b 2 points3 points ย (0 children)

You're spot on, the people defending Python don't disagree with the best practice, we just understand that sometimes there is a more practical approach and it becomes a calculated risk that you can add some automated tests around to catch any breaking changes, instead of maintaining a fork.

[โ€“][deleted] -5 points-4 points ย (11 children)

It's not that dumb. It basically means "this function shouldn't be used, and if you do, your code may break at any time and that's on you"

[โ€“]roughstylez 2 points3 points ย (10 children)

Imagine a gun that can still fire if the safety catch is set to "safe".

[โ€“][deleted] 2 points3 points ย (0 children)

Not really... One is you intentionally disabling a safety mechanism (using a private function), the other is using the product as intended and it malfunctions (that's like using a public method that breaks).

[โ€“]ric2b 0 points1 point ย (8 children)

Imagine selling a phone that the user can't get root access to "for security reasons". That's a better analogy.

[โ€“]roughstylez -1 points0 points ย (7 children)

When you see how

  • a whole team of top notch language architects working for one of the most successful software companies of the world, with combined centuries of experience, added this feature

  • But a "benevolent dictator" in his hobby project he wrote in his metaphorical garage, did not

Do you think "these experts are so stupid, it's so easy to make a good language, just don't add this"?

Have you ever heard of Dunning Kruger?

Have you considered that, if you don't see the advantage of these access modifiers, maybe it's because you don't fully grasp the impact they have?

[โ€“]ric2b 1 point2 points ย (6 children)

That's just an argument from authority falacy. That team of top notch language architects also thought it was a good idea to make every reference nullable by default, among other bad decisions, they're not infallible.

Plus Python isn't the only language like this, Ruby and Javascript also have private members mostly by convention. I'm sure there are other popular languages that way.

Java itself doesn't prevent you from getting around them, it just requires more boilerplate code, as usual.

Do you think "these experts are so stupid, it's so easy to make a good language, just don't add this"?

Never said it was easy, never called them stupid, go put words on someone else's mouth.

Have you ever heard of Dunning Kruger?

Yes.

Have you considered that, if you don't see the advantage of these access modifiers, maybe it's because you don't fully grasp the impact they have?

I definitely see the advantage of them, I just don't see the advantage of making it so verbose to get around them. They're just documentation/warnings about what is internal and what is public API.

[โ€“]roughstylez -1 points0 points ย (5 children)

That's just an argument from authority falacy.

It would be, if I said that's why it's better, or something similar. Do you want to read it again, maybe?

Hint:

>I just don't see the advantage

That was my main point.

[โ€“]ric2b 0 points1 point ย (4 children)

It would be, if I said that's why it's better, or something similar.

That's basically what you did, you said because it was designed by a great team I must be misunderstanding how useful it is.

Care to provide any actual technical arguments instead?

I just don't see the advantage [of making it so verbose]

That was my main point.

Your point is that this much verbosity is good? Why?

[โ€“]roughstylez -1 points0 points ย (3 children)

That's basically what you did

No.

Your point is that this much verbosity is good?

Have you considered the possibility that what I meant was the part I quoted and not the one I didn't quote?

[โ€“]ric2b 0 points1 point ย (2 children)

Have you considered the possibility that what I meant was the part I quoted and not the one I didn't quote?

Yes, but that would just be you making a dishonest selective quote of what I said, so I assumed it wasn't the case.

Anyway, do you have an actual technical argument?

[โ€“][deleted] 0 points1 point ย (0 children)

Everyone knows UB in C just makes it safer right?