r/firstweekcoderhumour 🥸Imposter Syndrome 😎 5d ago

[🎟️BINGO]Lang vs Lang dev hates Why are we using R again

Post image
134 Upvotes

109 comments sorted by

View all comments

64

u/dingwinger1225 5d ago

weird syntax, python is easier

im getting tilted by this, python's syntax is an unintuitive mess. people are just used to it

16

u/No_Departure_1878 5d ago

it seems intuitive to me, what do you find unintuitive?

26

u/EvnClaire 5d ago

dot underscore underscore name underscore underscore

14

u/No_Departure_1878 5d ago

those are dunder methods, the __name__ helps to keep methods that you are not supposed to touch most of the time separate from stuff that you normally would implement yourself. Most methods you would implement yourself are not supposed to look like that.

5

u/Salazar20 5d ago

Why they just don't do "_name"? If you call it from outside it looks bad like "thing._name" and then you know you fucked up

9

u/No_Departure_1878 5d ago

_name is used for protected attributes. Attributes that you are not supposed to access outside the class or its derived subclasses.

You care not supposed to call __name__ from outside. For example __str__ allows you to define what will happen when you do

print(object)

you never do:

object.__str__()

you just use 'print', same with __div__, __init__, etc.

1

u/Salazar20 5d ago

OK but why not use a single _ to say "this is protected" why does they need to have 2 ways of declaring outside protection?

The closest I have experience with is gdscript that presents itself as phyton like and they use _ for anything private

And if you want to modify the behavior of a subclass you simply write the subclass as a private class

4

u/riisen 5d ago
__thingieMajingie__ is language standard object methods 

_thingieMajingie is user defined "private" method.


Like the function str(variable) is the same as variable.__str__()

Or to call something like variable() is the same as variable.__call__() 

Its just standard object methods.

__name__ == "__main__" means that the file executed is this current file. Because the executed file and sub-files are all objects.

1

u/Salazar20 5d ago

So phyton really didn't want users to call the standards method so they made ugly AF? I guess it does gives it a easily parsed way to know what's yours and what's not

3

u/riisen 5d ago

Well i agree its ugly AF. But its possible you want _eq, _gt, _call or any other dunder method name for your object, this way they are available for your objects.

class Animal:
    def _call(aString):
        # this will not interfere with the underlying call method for an object and can be a specific method for animal.
        print(aString)

    def call():
        self._call("mjau or something")

1

u/No_Departure_1878 5d ago

I see it more as,

Make them hard to write, so that they do not get in the way of the user's normal methods and attributes.

1

u/Juice-De-Pomme 4d ago

In other object oriented languages, you can't access private methods/variables. Python differs from those languages (since it isn't object oriented but a lot of devs use it as such) as it lets you do it but at the cost of having to go out of your way to use them.

1

u/uslashuname 5d ago

Well it’s not protected, you can totally use it from outside

3

u/Salazar20 5d ago

Only if you ignore the error messages and warnings telling you to stop I guess? I assume phyton straight up don't allow using privates and in gdscript you can still power through them but... Why not use a simple _? They both seem to do the same stuff so why is phyton like that?

1

u/grizzlor_ 5d ago

Second time and third time you’ve called it “phyton”

>Why not use a simple _? They both seem to do the same stuff so why is phyton like that?

Single underscore is user private methods and double underscore is language private methods. The double underscore methods are mostly like class stuff that you override to specify custom sorting/comparison/etc.

1

u/No_Departure_1878 5d ago

Python allows you to do pretty much anything you want, including those methods directly. However that freedom means that you can do stupid things that will cause you troubles eventually.

That's the problem with python, it assumes you are an adult, and you know what you are doing. But python? The average python user is not a software expert.

1

u/Deep-Ad5028 4d ago

It is more fool-proof to make it awkward with 4 underscores.

It is easier to overlook single _

1

u/McNegcraft 5d ago

Because dunder methods are not private methods

2

u/Integeritis 5d ago

Seems like the language you love is missing something? I wonder what you could do instead of __x__. Hmmmm 🤔

2

u/garver-the-system 4d ago

sort being a free function instead of a member of list is pretty unintuitive for starters

If you don't know another programming language or what Python does under the hood with references, the very concept of mutable defaults and the list of types that are safe to use as defaults seem really unintuitive

1

u/No_Departure_1878 4d ago

I do not know what python you are using but:

```

x = [1,3,2] x.sort() x [1, 2, 3]

```

In python you do not make objects with'=', like the copy constructor in c++. You need to make the copy explicitly. Otherwise you only make new references. The mutable defaults is one of the few bad design instances in python that I can think of.

1

u/garver-the-system 4d ago

I'm probably using the version of Python from an alternate universe where sort is a free function but list is a member, can't imagine why else I'd get those mixed up

As fo the copy logic, I maintain it's unintuitive for someone who doesn't know why an object is different for a novice who doesn't know what a reference is or why a number behaves one way and a dict behaves another

3

u/leavemealone_lol 5d ago

{code if true} if condition else {code if false} as opposed to literally every other ternary operator. Even Excel formulas got it right. What a fuckass price to pay to get a language that “reads like english”

1

u/No_Departure_1878 5d ago

eat a pie if hungry else do not eat a pie.

vs

if hungry eat a pie else do not eat a pie

having hungry, the condition, the next to eat a pie, the value is somewhat awkward, the if separating them is probably the right choice there. Besides that, it does read like English.

1

u/leavemealone_lol 5d ago

Each and every other language uses one convention, and that is this:
condition, code if true, code if false.

Over the years, this becomes ingrained in non-python programmers. Then python comes along trying to be shakespeare:

code if true, condition, code if false.

When I remove the actual english aspect from the syntax, it looks awkward doesn't it? Python has "code if true" at the start. What is true? Something that is lexed after?

More importantly, when you're reading code, these syntax splits are made by english words. And its not easy to quickly pick out each part of the syntax when every lexical token is just english. And now, compare this to what other languages tend to do, like CPP. They use a ? to express a logical check- which itself is very easy to recognize, and then, to split the if true/if false code blocks, it uses a :. This is a far more effective separator than literal english words.

Hell, for the sake of the argument, lets take Rust. That thing doesn't have these ternary operators, and also uses english words as tokens. Yet, it is still extremely clear due to the format it uses:

condition {code if true} else {code if false}. Despite it also using English like Python, it still makes it very clear due to the *objectively correct* ordering, and the forced usage of {} for even a single expression.

1

u/No_Departure_1878 5d ago

Yet, it is still extremely clear due to the format it uses:

condition {code if true} else {code if false}. Despite it also using English like Python, it still makes it very clear due to the objectively correct ordering, and the forced usage of {} for even a single expression.

I do not understand what you mean, In python you do

name = 'charles' if person.is_male else 'mary'

that looks identical to your Rust example

condition {code if true} else {code if false}

in contrast c++ would be much less simple:

auto name = person.is_male ? 'charles' : 'mary'

to me the latter does not read as naturally as the former.

1

u/leavemealone_lol 5d ago

I think you are assuming something. I, along with many developers, do not want to "read" code "naturally" as english. This is programming, not poetry. Once you get used to programming conventions and syntax, your brain starts expecting things to be a certain way, and Python often breaks it. This includes things like these if else one liners, forced indenting, iterable-based loops instead of iterator-based loops and so on. One such "convention" that is deeply ingrained is the ordering, which everything other than Python follows.

Now to translate the example you gave in other languages (assuming is_male is a bool attribute of the person object):

Python:

name = 'charles' if person.is_male else 'mary'

CPP:

string name = person.is_male ? "charles" : "mary";

Rust:

let name: String = String::from(if person.is_male {"charles"} else {"mary"});

Now you can see how non-identical each code is. CPP and Rust may not "read" as "naturally" as Python, but you don't want that. You want structure, and you want to be able to find exactly what part of the code you need with the least effort. You can pinpoint where the condition of the code will be in CPP and Rust quickly (even with the condition itself being inside a String::from() function. But for Python, try it. You'll take slightly linger to piece together where the condition starts and ends than CPP and Rust.

1

u/No_Departure_1878 5d ago

It's a small difference if you look at the code. However even in your example of iterators vs ranges, you can also do:

for (auto &entry : mymap) { ... }

in C++. And this was introduced in C++ because it is an easier design than the iterators approach. I.e. many of the easy approaches of python have been carried over to other languages.

I think this is deeper than just consistency. What we are talking about here is efficiency. We want to spend the least amount of time and effort on syntax. Now that might mean:

  • Make the syntax easy to read and write, i.e. the python way.
  • Make the syntax the same as in every other language, so that I do not have to switch mental models, i.e. rust

I am not sure which is always the best approach. Some syntax is truly fucked up, like the c++

std::cout << ... << "\n";

and people have recognized and moved away from it. I kind of agree that python could have tried to put the condition as:

name = if person.is_male 'charles' else 'mary'

However I see cases like:

name = if x, 'charles' else 'mary'

where you have two values next to each other, i.e. a tuple x, and a string and it becomes ambiguous. And in cases like this, it's probably so close to other languages that it might not matter.

1

u/leavemealone_lol 4d ago edited 4d ago

in C++. And this was introduced in C++ because it is an easier design than the iterators approach. I.e. many of the easy approaches of python have been carried over to other languages.

What CPP did here is not a matter of principle, its just another updated tool into the already bloated CPP ecosystem. C traditionally relied on iterators and pointer arithmetic, and CPP has its roots tied there, a for each : iterable loop was added to modernize the language. In fact, to further defend your own point, Rust doesn't have an iterator loop, and it strongly encourages iterable loops.

So what point am I making here? It's not a language feature that I am worried about. Its the precedent the language is setting. Lets take Rust vs Python- the two languages which dont have an iterator based loops. Why do I still find Rust's precedent more agreeable than Python despite the both being the same? Because Python wants you to use this type of loop as a default. Rust on the other hand, actually encourages functional programming, using functional iterators like maps, filters, scans, folds, and such. When your default is this, and only in other edge cases when these iterators don't address your issue, do you use the iterable based for each loop. Python too has these functional tools in functools and itertools libs, but they are wildly inconsistent in many ways like their lazy evaluation policies, and their argument positioning. Guido van Rossum in fact, tried to totally remove functional iterators form Python, and only reconsidered after backlash. This is the precedent Python is setting. CPP on the other hand, lets you do whatever the fuck you want, it's bloat accomodates anything.

I think this is deeper than just consistency. What we are talking about here is efficiency. We want to spend the least amount of time and effort on syntax.

Exactly. That was my implicit point in my previous comment. You waste mindspace by switching mental models, as you've put it, when you are working with something unfamiliar. But here's the thing. Something like the Rust borrow checker needs not just a switch but a revolution of the mindset, but it is not a "one off thing", its a entire conceptual way of thinking. Meaning, if you learn borrow checker, you will take it with you to other languages, and even without a borrow checker, you will program in a defensive way that the borrow checker would've forced you for in Rust. A pythonic if else one liner on the other hand, is a "one off thing". There isn't a justifiable reason other than "it must read like English". If you learn the pythonic if else, and go to CPP, you will struggle. This is the reason why even a massive overhaul like Rust is praised while such a small convention change in Python is criticized.

Make the syntax easy to read and write, i.e. the python way.

Arguable, Python is not any more easier to write than any other language. Of course, due to it being dynamically typed, it is inherently less verbose, but the minute you start type hinting, you're reaching the same level of explicitness as other static typed languages. Hell, if you're using a library which doesn't type hint, you'll have to type hint more extensively in your code to compensate, making it far more unmanageable. Try typehinting a json object. As a matter of fact, try type hinting any function that returns Any.

Even if you disregard type hinting, python is still not any more easier to read and write. global? nonlocal? a lack of static types, and a reliance on decorators to compensate? non-private encapsulation? To bring P ython's functionality close to other languages, you'll have to do all kinds of fuckery, and the minute you do, your code complexity goes all the way up. Doing something as simple as a Rust enum requires you to define multiple python abstract classes for each variant and union them together into a new type: an incredible messy solution.

So Python is only easy to read and write as long as you script with it. Develop any kind of scalable and maintainable code, and you'll find yourself wishing you were coding in anything else.

I am not sure which is always the best approach. Some syntax is truly fucked up, like the c++

It's not. cout and << and "\n" makes perfect sense to me. cout is streaming to stdout, and << is the stream operator. Its very convenient to have a handy operator for streaming, because that is the primary way terminals interface with us. "\n" is just a newline, its used everywhere. You can also use "endl". "cout" is just console out, also another straightforward identifier.

I think I am finding this very straightforward because I used it a lot and I understand it's components, but in case you are a beginner, this might've been the first line of code you see in CPP tutorials, and you're rightfully confused.

where you have two values next to each other, i.e. a tuple x, and a string and it becomes ambiguous. And in cases like this, it's probably so close to other languages that it might not matter.

But it does matter. Yes, lets say python still does follow that specific order. It still is more unreadable compared to Rust solely due to the lack of {}. Like you said, when a tuple and a string are next to each other, but one is a part of a condition and the other is a part of conditional code execution, Python makes the distinction unclear, because it's trying to be English. Rust would have {}, and that will instantly split up the tokens and make it easier to "read".

1

u/ComprehensiveJury509 5d ago

It's more verbose than absolutely necessary, but I wouldn't file that under "unintuitive".

1

u/leavemealone_lol 5d ago

If you learnt any amount of programming languages before you touched python (which I did), you’d know how annoying this feature alone is to muscle memory. Unfortunately most people who are inexperienced end up learning python as their first language so they won’t see this issue, and most experienced end up never touching python to complain about it.

0

u/JonasAvory 5d ago

if true:

Hmm there’s a syntax error here, and python won’t even complain before reaching this line

2

u/No_Departure_1878 5d ago

You mean because you do not have anything inside the if? Right, python is an interpreted language, you cannot compile it and get the compiler to show you the problem. The problem will show up when you actually run the code. That's how interpreted languages work.

The problem is that you are not using the right tooling, you are supposed to use a static type checker and a linter, e.g. pirefly and ruff. If you that, you will see:

Expected an indented block after `if` statement

as soon as you write that if.

I see that many of the frustrations that you have with python stem from the fact that you do not know how to use it properly.

1

u/ummaycoc 4d ago

Languages are syntax and semantics. A common translator for python is an interpreter.

0

u/JonasAvory 5d ago

See you don’t even see the problem I meant. „true“ is not a valid Boolean expression in python

2

u/No_Departure_1878 5d ago

Then that's the same thing. You are using an undeclared symbol and the type checker/litner will tell you:

Undefined name `true`

as soon as you make the mistake. You are just not using the right tools.

1

u/SimonHauguel 4d ago
  1. This is not a syntax error
  2. Python does report syntax error before the code execution
  3. Just use a linter like everyone else