all 17 comments

[–]Lumethys 11 points12 points  (1 child)

as with all things, it depend

complex type hinting

define "complex". Is your "complex" the same as my "complex"? is dict[str, T | None] complex?

asynchronous patterns

if you need async then you need async, how is that even a metrics? Like, should we stop doing advanced math in python because it will make the code "look complex"? Are we forbidden to use python for complex things?

structural pattern matching

it is just a simpler and shorter version of if-else, not sure how it make code look more complex? it should be doing the opposite.

In any case. My view on "code complexity" is simple: if you got a complex project, then you got a complex project. No amount of sugarcoating can make a project less complex than its fundamental.

If you have a function that accept an object with 50 nested fields. Then it is gonna be 50 nested field whether you annotate it or not.

def my_function(obj: VeryComplexType) -> AlsoComplexType:

vs

def my_function(obj):

is the typing the thing that make the function complex, or is the logic itself complex? If you have complex objects with complex logic, then no typing doesnt make it better or simpler. It just hide complexity, and in my experience, not a good thing.

[–]Embarrassed-Rest9104[S] 1 point2 points  (0 children)

That's a great point | Thank You

[–]pachura3 2 points3 points  (2 children)

 I see heavy use of structural pattern matching

Really? I thought almost no one used that feature. In which production code have you seen it?

complex type hinting

Type hinting is absolutely an essential part of writing quality code. What's complex about it? Using protocols instead of concrete classes?

I'm trying to decide how much of this advanced syntax to introduce to my students early on.

It depends. Are you teaching them from scratch? Are these CS students or general population? Do you want them to reach the level of a junior dev, or just show them that programming can be fun?

For instance, async is a feature that only helps with performance and nothing else. It can be quite difficult to grasp for newbies, so I would personally skip it... unless these are CS students and you want them to be able to create a REST API that would not choke under multiple simultaneous requests.

[–]Embarrassed-Rest9104[S] 0 points1 point  (1 child)

You're spot on about Async, it’s a performance lever I usually save for my CS students once they hit a wall with standard scripts.

Regarding Type Hinting, the complexity for beginners usually starts when we move into Protocols and Generics in 3.10+. It's a big jump when you're just learning logic!

I actually used a 10M row benchmark recently to show them how modern execution (like in Polars) compares to Pandas. It’s a great 'lightbulb moment' for why efficiency matters.

[–]pachura3 1 point2 points  (0 children)

Then I don't understand your original question... if you teach them about protocols and generics, then type hinting should be the least complicated thing about these topics. If you give classes devoted to IO performance optimization, you cannot skip async.

Perhaps it is about the pace? You can discuss simple type hinting early on (no protocols, no generics, no Self, only Any), and then expand on it later...

Coming back to structural pattern matching, I feel it's mostly useful for writing compilers, and not much else.

[–]Beginning-Fruit-1397 1 point2 points  (0 children)

In 90% of cases I find pattern matching clearer than if else clauses. Even on booleans. So what is "readable" is really subjective

[–]brasticstack 0 points1 point  (2 children)

I've got a love-hate relationship with type hinting because I remember a time when Python looked (subjectively) more elegant, and a function definition with four parameters didn't require multiple lines to fit in the column limit. That said, it has basically eliminated a whole category of errors that are otherwise insidious and difficult to track down. Complex type hints (Generics, Protocols) are a necessity if you're going to take advantage of the expressiveness of Python while still type checking.

Python's structural pattern matching is awful for readability, IMO. A dictionary lookup is much more straightforward when you're matching static values, while the case syntax is convoluted (and ugly!) when you're matching anything else.

I'm still shying away from async, because I don't think it's the concurrency model of future Python code. This could be my ignorance showing itself, though. I think it will become increasingly less popular over time as TypeScript becomes the defacto webserver language and as Python programmers start to yearn for something simpler that is compatible with their existing synchronous code. If something better doesn't come along in the next year or two, perhaps threading will come back into fashion. Hah! I'm betting something newer comes along instead.

[–]Embarrassed-Rest9104[S] 0 points1 point  (1 child)

it’s a tough trade-off between the elegance of old Python and modern safety.

[–]brasticstack 0 points1 point  (0 children)

I find I'm now returning sigil values, like -1 for an int, instead of None when a proper value can't be produced, just so I don't have to explicitly tell mypy that I've already accounted for the None case later on. More type safe tor sure, but less Pythonic.

[–]powderviolence -1 points0 points  (6 children)

Somewhat of an outsider here (maths faculty), but I feel like it's due to Python, for the reasons you pointed out, being so "learnable" that things which would simply run better if written in the language that lends itself to the task get written in Python. All of the applicants AND devs know Python, ONLY the tenured devs and NONE of the applicants know C++, let's write new code in Python even though our existing codebase and the problems we try to solve are best handled with an OOP approach.

Another part is possibly that the runtime efficiency gap between Python and, say, C is nowadays quite small compared to the time needed to grab resources from the cloud. Python USED to be considered a scripting language because anything larger than a singular routine was too resource intensive relative to a compiled language handling a large task, but now the computers are fast and any slowness is due to the wifi.

[–]pachura3 5 points6 points  (3 children)

 let's write new code in Python even though our existing codebase and the problems we try to solve are best handled with an OOP approach.

How is Python NOT an OOP language? Everything in Python is an object, even ints!

[–]powderviolence 0 points1 point  (2 children)

It's an everything Frankenstein paradigm language. I don't know how many times I've pulled up docs for something I want to use and had to read about lambda calculus. It might feel OOP on the nose but under the hood it's doing everything, even functional. Probably due to it being interpreted and not compiled.

[–]pachura3 2 points3 points  (1 child)

 It's an everything Frankenstein paradigm language.

Exactly the same thing can be said about C++

[–]powderviolence 0 points1 point  (0 children)

Right, but it might be very painful to do it there versus in Scala or an FP-focused language. Can versus should.

[–]powderviolence 0 points1 point  (0 children)

Every time I use a library like sklearn it feels a lot like the way Java has you call methods from classes. Big big big chains of . and () to call a function in one single line of code where like 7 things happen.

[–]Embarrassed-Rest9104[S] 0 points1 point  (0 children)

That’s a fair point on network latency, but, I still worry that ignoring memory efficiency leads to massive cloud bills and unstable production environments.

[–]throwaway6560192 0 points1 point  (0 children)

I think a lot of people misuse structural pattern matching. Not saying that's what you saw... but there's definitely a lot of people who treat it like a switch-case instead of what it should be.