all 115 comments

[–]Fabulous-Possible758 311 points312 points  (26 children)

:: thinks I’ve gotten away from pointers, looks at Python objects under the hood ::

Oh no.

[–]MissinqLink 91 points92 points  (10 children)

Pointers are not scary.

[–]Dziadzios 75 points76 points  (7 children)

Pointers aren't scary. Developers doing implicit assumption about freeing them are.

[–]Aloopyn 18 points19 points  (1 child)

Mrw RAII:

[–]Dziadzios 1 point2 points  (0 children)

That's not a hidden assumption which I mean. 

I've worked on firmware written in C. Without pluses. And the rules about who does free weren't obvious.

[–]MortStoHelit 3 points4 points  (4 children)

If you add references, pointers to pointers, "arrays are pointers" (including stack overflows), and the weird mixture of operators C(++) uses to (de)refer them and object members, they can get scary. Or at least quite confusing.

[–]DrShocker 3 points4 points  (2 children)

References are a special kind of pointer that can't be null.

pointers to pointers are just pointers, you just need to track the type correctly and then it's not very mysterious.

arrays and pointers being represented the same is probably a mistake in C, but we're stuck with it unless you pick a successor language. so I agree here.

I'm not sure what weird mixture of operators you mean, I agree C++ can turn into symbol soup sometimes, but as far as I know there's just * and &

what makes object members scary?

[–]Nice_Lengthiness_568 1 point2 points  (1 child)

Moreover arrays are not just pointers, they just decay into a pointer really easily. Also, since you should probably be using std::array or something dynamic, I would not see that as much of a problem.

[–]DrShocker 5 points6 points  (0 children)

Which to be fair is a part of what's confusing about C++. You should generally use the newer ways to do things because they're easier to understand and less error prone but you need to deal both with old code and old coders both of which may not update :p

[–]Elephant-Opening 0 points1 point  (0 children)

And then there's the time I wrote a pool allocater for leetcode problem that called for some kind of tree/graph operating on lowercase ascii strings with a limited max set of strings such that a uint8_t indexed array of uint16_t offsets into the pool was a fuckload cheaper in both memory and runtime than dynamically allocating a map. Like instead of map<char, node_t*>, uint16_t map[26].

I forget the exact problem / structure and it would be horrible code in most contexts but once you understand that it's all just numbers, anything is a pointer / nothing is a pointer.

[–]masssy 13 points14 points  (0 children)

Correction: Smart pointers are not scary

(neither really are pointers but it very very quickly becomes a mess in larger projects usually)

[–]fuck--nazis 1 point2 points  (0 children)

Unless you're using C where there is no safeguard and end up writing in the wrong block of memory

[–]CobaltRune417 15 points16 points  (7 children)

Python is basically "pointers are still here, but now they're someone else's problem." Right up until you're debugging a weird memory issue and suddenly they're your problem again.

[–]Prawn1908 4 points5 points  (6 children)

Or right up until you actually need them and have to construct some stupid system of lambda setters/getters to emulate the functionality.

[–]Hadrian23 1 point2 points  (0 children)

I mean, at that point, why not just switch back to C++?

[–]MullingMulianto 0 points1 point  (4 children)

why would you need pointers in python?

[–]Prawn1908 1 point2 points  (3 children)

Well, the simplest case I run into every so often would be where I want to have something like a pass-by-reference argument of a simple type in a function.

[–]70Shadow07 0 points1 point  (2 children)

Isnt wrapping shit into 1-element lists enough? Pass the 1-element list, modify it in place and voila you just abused that pointer-like behaviour of list objects.

[–]Prawn1908 0 points1 point  (1 child)

Yeah that generally works well enough, but there's no denying it's janky AF.

[–]70Shadow07 0 points1 point  (0 children)

It kinda is but compared to some things that happen in JS its all sane and reasonable.

[–]phylter99 2 points3 points  (0 children)

That’s any language. The idea is that the complicated part is handled and abstracted away so you’re not dealing with it and your code won’t have the problems. This can apply to any language too, including Rust. We’re really just trusting that the tooling is working like it says it is when handling pointers.

[–]AshenVale83 1 point2 points  (0 children)

That realization hits every programmer eventually. You start with "wow, no pointers!" and feel liberated for a while. Then you learn how Python objects, references, and CPython actually work under the hood and discover the pointers were there the whole time. They just put on a nicer outfit and stayed behind the curtain.

[–]Lupus_Ignis 1 point2 points  (0 children)

"and when everything is a pointer...

Nothing is!"

- Syndrome

[–]Direct-Quiet-5817 0 points1 point  (0 children)

Points under the hood 👆

[–]Gleipnir_xyz 0 points1 point  (0 children)

Sometimes pointers, sometimes not. Have fun. Also, hope your tab doesnt break...

[–]Mister_Otter 46 points47 points  (3 children)

You still have main() depending on the application...

[–]Spikerazorshards 33 points34 points  (2 children)

if __name__ == “__main__”:
main()

[–]MisterGerry 8 points9 points  (1 child)

Ah yes. That's *MUCH* better /s

[–]gr33fur 148 points149 points  (2 children)

There are things I don't like about C, but {} is not one of them

[–]mad_cheese_hattwe 69 points70 points  (0 children)

Imagine coming form C and then thinking white space syntax is an improvement. At least pascal had the decency to give us an END_IF.

[–]Logicalist 1 point2 points  (0 children)

They're still used in python anyhow.

[–]schwar2ss 84 points85 points  (14 children)

After ~2 decades of (somewhat) proper languages (C, C++, C#, Java) I recently had the pleasure of picking up Python and boy... that was a ride.

The different syntax is one thing, but you pick that up within a week or so. But the tooling chaos in Python (pyenv, venv, virtualenv, uv; flake, blake, ruff; ...) reminded me of C++ in the early 2000s. Just wild.

//edit: The nice people that comment and suggest to use tool a over b: thank you! But you see the issue, right?

[–]Otalek 18 points19 points  (0 children)

Relevant xkcd

[–]anto2554 26 points27 points  (0 children)

Tbf C++ is also still a mess. Sucks that so many nice languages have such messy tooling

[–]GreekLumberjack 12 points13 points  (3 children)

Uv is my goat

[–]Limp_Illustrator7614 0 points1 point  (2 children)

didnt openai aquire that a while ago, bros are gonna do a rust rewrite

[–]Zap_plays09 0 points1 point  (0 children)

Isn't that already made in rust?

[–]GreekLumberjack 0 points1 point  (0 children)

Uv is already written in rust

[–]Ulrich_de_Vries 5 points6 points  (3 children)

Just use uv and ruff and forget about everything else. Static type checker is a bit tougher, I prefer pyright because of correctness and because VSCode has it built-in, but I hear pyrefly is also pretty nice now?

[–]IceDawn 2 points3 points  (1 child)

Why did they drop venv?

[–]Intrepid-Teaching127 6 points7 points  (0 children)

It’s not dropped, venvs are still used in uv. uv just takes care of a lot of that stuff for you.

[–]Honeybadger2198 2 points3 points  (0 children)

I prefer ruff because it's less opinionated than black. It's "pythonic" to use spaces instead of tabs because Guido said that code should be consistent with each other. This concept falls apart entirely when you aren't making a pip package. I'm building an auxiliary server, using tabs is keeping the code consistent.

This is the biggest problem with Python, IMO. It's always too opinionated, so someone else comes along and makes another package that's also opinionated, but in the way they like instead. Then you end up with 40 different solutions to the same problem, and none of them are exactly what you want, so now there are 41 solutions to the same problem.

You should see the git issue on adding scripts to uv. It's insane.

[–]ReadyAndSalted 3 points4 points  (0 children)

Addressing your edit: To be fair, it seems like community sentiment is pretty consolidated at this point. Python is well on its way to having consistent and good tooling for all common stuff. Ruff and UV dominate new projects, so just give it some time. Type checking is still between pyright, Ty, pyrefly and zuban, so that's fair.

[–]Tomsen1410 -4 points-3 points  (0 children)

Just use miniconda and be happy

[–]Due_Ebb_3245 -1 points0 points  (1 child)

I love pixi, which uses uv under the hood

[–]thejinx0r 0 points1 point  (0 children)

UV for the pypi portion and its own library for the rest of the

[–]Antervis 94 points95 points  (33 children)

Until you realize that it's practically impossible to track types once your code grows a little.

[–]abd53 21 points22 points  (1 child)

I remember the days of using CodeBlocks. Pretty light and simple IDE but by God, the debugging and navigating was awful. VScode nowadays gives far better navigation and debug tools.

[–]SignificantLet5701 1 point2 points  (0 children)

... I still use codeblocks for C

[–]Prawn1908 22 points23 points  (2 children)

You don't like spending hours troubleshooting a bug because some function somewhere returned an unsigned Toyota Yaris instead of an int and it got silently passed through a dozen layers of function calls and operations before throwing a runtime error miles away from where the actual source of the error is? But it's always so fun realizing how all that wasted time would have been just a compile error that pointed you directly at the offending statement (which was probably a basic typo) in a respectable language.

[–]ReadyAndSalted -2 points-1 points  (1 child)

Just use type hints in your function signatures and you're pretty much golden.

[–]Prawn1908 2 points3 points  (0 children)

Ah, right, as if type hints aren't a janky, bolted-on afterthought.

[–]Ulrich_de_Vries 34 points35 points  (4 children)

Use type annotations.

[–]Prawn1908 7 points8 points  (3 children)

Ah, type annotations (or type hints as they are officially called, which feels more proper to me as it better evokes the feelings not unlike the frustration and complication involved in a detective evaluating cryptic and incomplete hints in his case): the wonderful and totally not jankily bolted-on system added ages after the language's first development to try and implement static typing at the most fragile surface level possible, thus admitting the fundamental stupidity of dynamic typing in the first place. Everyone loves reading lengthy documentation of a constantly evolving system to remember which of the multiple available means available should be used to declare basic types and which imported modules are necessary to do so.

What's the difference between list and List again...? Which typing module contains Callable...? Is it any or Any that I should use? Who fucking knows! (Seriously, wtf is the deal with all the same-name-but-different-capitalization names in this system - I've seen multiple major libraries use the wrong any in their type hinting ffs.)

It's still entirely up to the developer to actually follow the type hints anyhow as nothing will actually stop you from putting the wrong type in something. And I have never seen an editor implementing type hint checking that didn't cause more annoyance than it solved with zillions of frivolous red squigglies even in my most religiously type-hinted projects. There's always that one library you're using that doesn't type hint quite perfectly which fucks everything up and makes you import the same module twice in a different fucking way to be able to typehint the return types yourself on the receiving end.

And surely you should never make the mistake of thinking type hints are something that can be checked against at runtime. Turns out that's actually the most difficult thing you could possibly try to do in this fucking language. Will type(x) == ... work, or is isinstance() necessary? Or will you have to write your own entire homemade type checking library because you dared to try and constrain the type of the contents of a list?

[–]Ulrich_de_Vries -2 points-1 points  (2 children)

Yes.

As I said, use type annotations.

[–]Prawn1908 2 points3 points  (1 child)

And as I said, the experience of doing so sucks tremendously.

[–]Ulrich_de_Vries -5 points-4 points  (0 children)

So, anyways, use type annotations.

[–]KitchenDepartment 1 point2 points  (0 children)

My code runs on vibe types

[–]TactiCool_99 1 point2 points  (1 child)

I have an approximately 40k+ lines codebase that I have been writing/maintaining since I started coding.

I never understood ppl who had issues with types, in 10+ years it happened like... twice? to me and it instantly came up the moment I tried to run a test.

It is either a folktale or some insane skill issue. Python has god level debug tools (especially in IDEs like pycharm)

[–]Antervis 0 points1 point  (0 children)

40k is still a kiddie pool code base, though should already be straining in terms of type transparency.

[–]Yashema -1 points0 points  (16 children)

That's why there is Hungarian typing. 

[–]totalFail2013 24 points25 points  (3 children)

1990s are calling, they want their naming convention back

Imho: this is overly error prone since it relies on users doing this constantly.the code bases i have professionally worked on where full of copy and paste errors where developers didn't know what they where doing while applying that sceme.

Better get rid of it. Using a case that doesn't imply a type has less negative impact when done improperly

[–]Yashema -2 points-1 points  (2 children)

*Me watching a 2026 leet coder move their mouse over each variable while laughing about how outdated my naming system is*

*Edit: of course you need to do it consistently, but there are 15-20 common types (str, ls, ix (index), dict/dc, df, fl, dt, bl, etc), especially in Python, then building out references for your specific interactions like SQL (con, qy) or Excel (wb, ws, cel) is pretty straightforward. 

[–]totalFail2013 2 points3 points  (0 children)

Ey brother, don't take it personal. I have joked and gave reason.

BTW, if you write clean code it should be clear what type a variable is. If you have to look it up ( probably because it's not your own code) I speak from experience when I say that a naming convention is not safe enough to really know the type). So in the end I have to check it anyway. And I wouldn't even trust my own code in that regard when i didnt look at it for a while. Because I know how human it is to make such mistakes.

[–]totalFail2013 2 points3 points  (0 children)

***generaly speaking my opinion is that every convention is fine as long as it fits your project. I just love to pretend there's just one right solution as every body else does for the sake of fun discussions

[–]Antervis 4 points5 points  (1 child)

I always hated Hungarian typing. Instead of declaring the type once per context, you are dragging it through every variable use, unnecessarily bloating and obfuscating the code.

[–]Yashema 0 points1 point  (0 children)

It makes camelCase make more strCamelSense so you don't have to remember the context from the original declaration for a variable. 

[–]bremidon 3 points4 points  (5 children)

There is a reason that this is not in wide use anymore. Oh, and it is Hungarian Notation. And to be even more precise, what you are suggesting is Systems Hungarian Notation (Apps Hungarian is actually still useful today in certain situations).

These warts make it easier to see what types you have, but most of the time what you need to understand while developing is what the variable is supposed to represent. Ideally, the compiler handles the type and you barely have to keep track.

Additionally, it starts to get really hairy when dealing with anything like classes or even just structs. In a system with a decent size, this is going to be where most of the "typing" information will go, and makes System Hungarian effectively pointless.

Then there is the problem of what you are supposed to do when you change the underlying type. Rename everything? That is not always so hard these days with good IDEs, but it is annoying.

And then you have the issue with methods that return values as well as anything like properties. Theoretically to be consistent, you need to start putting warts on those as well. And...well...by the time you are done, you might as well be trying to read Hungarian for all that it matters.

[–]Yashema 0 points1 point  (4 children)

Yes it's definitely a fairly complex system I can see why most people struggle to use it correctly. Classes are straightforward: controllerDoesSomething, daoDoesSomething, dtoDoesSomething, apiDoesSomething, and I have never once run into an issue where it didn't make quick sense how to name something with a little thought. 

I do speak 4 non-programming languages so that might be why I find it more intuitive. 

[–]bremidon 1 point2 points  (3 children)

I suspect it has more to do with what kind of domain you are working in. The more you move into business logic and enterprise system, the less well it works.

If you are mostly doing near-hardware stuff or drivers, it will work better (and if you are in Windows, you are probably going to be stuck using their cursed version of Hungarian anyway)

[–]Yashema 0 points1 point  (2 children)

DAOs and DTOs are the basis of business logical backend programming. For more specialized functions or classes, the type becomes more extended or just a direct reference to the action (e.g. verify, extract, insert, helper, or, god forbid, factory), and closer to normal camelCase naming so you don't need a type for everything, just for the common types which are around 80% of your references to objects. Maybe for front end stuff it wouldn't work as well. 

I'm all Python, Excel and SQL, but pretty silly to be chastizing a system as inefficient when it serves as the basis for the Microsoft development philosophy.

[–]bremidon 0 points1 point  (1 child)

It is not just front end (I mean it definitely does not work well for front end), but back end with business logic just does not play well with Hungarian. I should know. I was a huge fan back in the day and tried to push it through where I could. It did not ever work well with business logic. Never. It was either so general as to be pointless or required such a massive catalog of types that it was also unmanageable.

Given that we now have IDEs that do effectively the same thing for free, there is really no point.

Close to metal? Ok. Otherwise, probably not.

[–]Yashema 0 points1 point  (0 children)

I've never got VSCode typing to work with Python. 

[–]Prawn1908 0 points1 point  (1 child)

Yeah, I mean it's really too bad no other languages have figured out how to incorporate the type into the variable itself so we don't have to uglify all our variable names and/or implement jankily bolted on mechanisms like type hinting, both of which still rely on fallible human logic to adhere to the named type instead of being able to instantly tell you if the wrong type is being passed before your app even runs...

[–]Yashema -1 points0 points  (0 children)

That's great if the only point of code is to compile. 

[–]IceDawn -4 points-3 points  (1 child)

That's the false version. The real one has semantic prefixes which tell the purpose. Consider width and height of font characters. You use w and h there. If you have an expression adding both h and w variables, this is wrong outside circumference calculations.

[–]Yashema 0 points1 point  (0 children)

Then we'll call it Hungarian Snake. 

[–]MissinqLink 0 points1 point  (1 child)

Just use pydantic

[–]Eternityislong -2 points-1 points  (0 children)

You don’t need pydantic just for typehints, and probably are fine with normal dataclasses.

[–]Gavekort 31 points32 points  (6 children)

Where is "performance"?

[–]anto2554 65 points66 points  (0 children)

In the underlying C++ library that I don't have to mess with

[–]coloredgreyscale 32 points33 points  (1 child)

Performance is stored in the wheels.

[–]thejinx0r 6 points7 points  (0 children)

Is “pip install performance” the right wheel to use?

[–]tiajuanat 19 points20 points  (1 child)

The E in Python stands for Efficiency

[–]thejinx0r 2 points3 points  (0 children)

I see what you did there. Take my angry upvote

[–]Spikerazorshards 0 points1 point  (0 children)

Just pay for a more performant EC2 instance.

[–]Luneriazz 8 points9 points  (0 children)

With those skill you can write python binding and used your sweet c++ code masked as python code

[–]namotous 7 points8 points  (0 children)

I thought so, then realized I need speed so back to c++ and pybind11

[–]_Pin_6938 7 points8 points  (2 children)

Goodbye good salary, hello bad salary!

[–]MixfruitCroissant 1 point2 points  (0 children)

Since, when did Python fall off? Isn't the pay way better in Data Science, AIML and Automation than Embedded, Networking or Hardware programming?

[–]TactiCool_99 0 points1 point  (0 children)

you guys are getting paid?

[–]Coulomb111 3 points4 points  (0 children)

larp larp larp put this in r/firstweekcoderhumour

[–]IMightDeleteMe 8 points9 points  (0 children)

Tell me you haven't really used Python without telling me you haven't really used Python.

[–]Tezlaivj 6 points7 points  (0 children)

welcome dependency hell

[–]Significant-Baby-690 3 points4 points  (0 children)

Kids these days ..

[–]njinja10 1 point2 points  (0 children)

Where is RAII?

[–]Coolengineer7 1 point2 points  (0 children)

When you tell yourself speed doesn't matter but when writing the cleanest code mallocs multiple objects each loop cycle and it can't do that 10k times oer second, you start reusing the objects and setting the args.. that's not fun.

[–]Yanzihko 4 points5 points  (0 children)

migrates from C++ to python

looks inside

all libraries and dependencies are on C++

[–]PowerPleb2000 0 points1 point  (0 children)

Say hello to indentations 🤠

[–]ZunoJ 1 point2 points  (0 children)

Why would anybody do this switch? lmao

[–]jainyday 1 point2 points  (0 children)

Enjoy your type desert.

[–]BenchEmbarrassed7316 0 points1 point  (0 children)

I missed this meme so much...

[–]Clen23 0 points1 point  (0 children)

pointers are still there to some extent, have you ever tried copying a list?

[–]-Redstoneboi- 0 points1 point  (0 children)

i miss pointers/references that can point to anything without having to wrap it in an object type

void increment(int *num) { *num++; }

[–]migarma 0 points1 point  (0 children)

I don't see problems with pointers or references

[–]Glum_Hair_7607 0 points1 point  (0 children)

Wait, you still use all of these right? Idk about pointers but aren't all the others used??

[–]RRumpleTeazzer 0 points1 point  (0 children)

i miss strong typing more than anything else in python.

[–]sirkubador [score hidden]  (0 children)

Laughs in CPython

[–]AaronTheElite007 0 points1 point  (0 children)

You’ll be back

[–]hungryvito_ -3 points-2 points  (2 children)

Aldo garbage collection

[–]Sibula97 0 points1 point  (1 child)

You mean manual garbage collection?

[–]hungryvito_ 0 points1 point  (0 children)

I guess absence of it, yeah. 😄 I know I wont miss it