7 ms·
Returns: Brings functional programming to Python land
- rkangel 3y agoMy team has just spent 20 minutes trying to work out if this library is satire. I love functional programming (use Elixir at work a fair amount), but almost every one of these examples is harder to read than than the equivalent "classic" Python (https://returns.readthedocs.io/en/latest/ https://returns.readthedocs.io/en/latest/). Plus, if you're going to write Python then deviating majorly from the normal approaches is going to require maintainers to learn a whole new way of doing things. Given the tools that Python provides, I don't think that's worth it for the benefit. Perhaps for some specific applications?
- steinuil 3y agoThere's libraries like these for many languages and no, they are not satire. I see it as a misguided attempt to bring some patterns from languages that are "better" (by some metrics) into a language that doesn't have good support for them. By my experience, younger programmers are more likely to want to do this. I fell into this trap myself with a similar library for TypeScript, and discovered the hard way that code written this way was much less readable and debuggable. Less readable because you're essentially reimplementing variable assignment and control flow with lambdas and bespoke syntax that looks out of place. Less debuggable because the stack traces from these things blow up exponentially, and make it very hard to understand where an error came from. So yeah, it's not satire, just misguided. If you have to use Python you're much better off sticking to the usual patterns and apply more static analysis on top rather than trying to reinvent the language this way.
- rkangel 3y agoDupe of: https://news.ycombinator.com/item?id=39432843 https://news.ycombinator.com/item?id=39432843
- infecto 3y agoI am by no means the best to judge functional programming implementations but I find the examples provided as pretty confusing. The parts where the library is supposed to make things better actually look worse to me. The original Python examples also looks like cherry picked code that was already not written very well. if user is not None: balance = user.get_balance() if balance is not None: credit = balance.credit_amount() if credit is not None and credit > 0: discount_program = choose_discount(credit) I would probably write the python closer to this for readability. Don't judge me too harshly I just rewrote this quickly. if user is None: return balance = user.get_balance() if balance is None: return credit = balance.credit_amount() if credit is not None and credit > 0: discount_program = choose_discount(credit)
- NoboruWataya 3y agoWhat I really want (but Python doesn't have) is: credit = user?.get_balance()?.credit_amount() if credit is not None and credit > 0: discount_program = choose_discount(credit)
- Izkata 3y agoI swear I remember once seeing a library that enabled this by wrapping the first object: Foo(user).get_balance().credit_amount() Maybe with an additional .get() at the end to unwrap it? Though I imagine a dynamically-created class could avoid that.
- hprotagonist 3y agohttps://peps.python.org/pep-0505/ https://peps.python.org/pep-0505/ there's a PEP. But it's been pocket-vetoed, i think.
- BerislavLopac 3y agoIMO, the problem with the original code is not in the way it nests ifs, it's in the bad design. If it is properly nested in a function, user should not ever be None (any user-less behaviour should be in a completely separate execution branch, likely in a different module), while there is no reason for get_balance and credit_amount to ever return None.
- roger_ 3y agoPretty hideous IYAM. optional.py seems to address the same issue and with a slightly better approach (but still ugly). https://github.com/Python-Optional/optional.py https://github.com/Python-Optional/optional.py
- johnday 3y agoThis seems like too much effort has been put into it for it to be a purely satirical exercise, but I really cannot see why anyone would prefer to use this within Python, rather than (say) reaching for a proper type-safe functional language and either using that directly, or calling out to it from Python code. As a person who teaches functional programming at degree level, this is the kind of thing that would put people off FP before they even get in the door. It is obviously less ergonomic than standard Python, and the code you end up with is no safer or more abstracted than what you started with. That said, if the authors really do think it's a better way for programming in Python, and it works for them, then more power to 'em.
- dlahoda 3y agoi have fastapi server which gets and mangles data. and calls numpy with that. data is badly formatted, i need to make it right. functional code is better for that. i do not want one more service now to be added in typescript, with effect ts. there are no apis for haskell or other functional langs for data i need.
- deleted 3y ago[deleted]
- bradrn 3y agoI completely agree with you. As a Haskeller, I find it immensely irritating when people try to force ‘FP’ into programming languages where it doesn’t fit. It just ends up putting people off functional programming, which is a very nice paradigm in languages which properly support it. I feel that the best code is that which adheres to the general paradigm and style of the language it is written in, and these kinds of libraries go against that. What’s worse, these versions of ‘FP’ often bear very little resemblance to actual functional programming and its advantages. Rather, people seem to fall into the trap of confusing functional programming with ‘those fancy words I hear from Haskell’. Now, I may like Haskell, but its concepts are only useful because of the rest of the language — you can’t just port ‘monads’ and ‘IO’ into some random language and expect them to be usable. It looks like this library partly avoids that fate, in that it does have more than just ‘monads’… but yes, the monads are still there, and they’re just as clunky as you’d expect from Python. </rant>
- PaulHoule 3y agoNone is the third-worst mistake in computer science, Maybe is the second-worst, the Result that can contain either a result or an exception is the worst. I have debugged so much code that does the wrong thing with a Result (or other error handling). I will always remember the engineering manager who boasted about how we (1) did careful error handling with monads and (2) did code reviews. Oddly though I never got my code reviewed and I found so much code that silently dropped errors out of carelessness to believe there had never been code reviews. In my experience given a malfunctioning Scala class you can: (3) screw around with it for a few days or (4) write it in Java and have it working in an hour. (A counter to this is that sometimes you do want to send a result-or-exception to some other part of the program that involves storing it somewhere and Result is really great for that… but please learn to get over any fear of exceptions you have and ignore the people who want to stigmatize them.)
- hnfong 3y agoWhew! <- The sigh of relief after reading comments here and realizing that I'm not the only one preferring the standard style of writing Python instead of this "functional"(??) style... I get that Optional return values can force the programmer to handle errors without resorting to exceptions, but I can't help but wonder whether the first example with all those `bind_optional` ... is just Objective-C's nil messaging in fancy disguise... FWIW in Objective C this is exactly what one writes (even if those functions can return nil): credit = user.get_balance().credit_amount() if credit > 0: discount_program = choose_discount(credit) I'm not sure what's so "functional" about it though.
- emblaegh 3y ago> I'm not sure what's so "functional" about it though. This is a library about composing function, can't get more functional than that.
- davidfstr 3y agoLooks like this library is serious. Most of what I see can be written more succinctly using existing Python functionality: 1. Maybe -> Optional[T] 2. Result -> Union[SuccessT, FailureT] 3. Future, FutureResult -> concurrent.futures.Future[T] 4. IO -> don't use this; none of the standard library I/O supports it I do appreciate the use of "container" as a term instead of "monad". I also appreciate the typechecker enhancements being put forward by their custom plugins.
- BerislavLopac 3y agoI believe the recent idiomatic recommendation for the first two is to use the union type expression: 1. T | None 2. SuccessT | FailureT
- epgui 3y agoThis is potentially quite helpful, but would you happen to have a source for that?
- TrickardRixx 3y agoThe Union Type PEP[0] suggests that the "bitwise or" syntax is equivalent, but cleaner than typing.Union [0]: https://docs.python.org/3/library/stdtypes.html#types-union https://docs.python.org/3/library/stdtypes.html#types-union
- epgui 3y agoThanks! I missed that.
- BerislavLopac 3y agoThey're both perfectly valid; but the expression style [0] is shorter and more obvious, especially compared to Optional. Even the documentation for Optional states [1]: Note that this is not the same concept as an optional argument, which is one that has a default. [0] https://docs.python.org/3.11/library/stdtypes.html#types-union https://docs.python.org/3.11/library/stdtypes.html#types-uni... [1] https://docs.python.org/3.11/library/typing.html#typing.Optional https://docs.python.org/3.11/library/typing.html#typing.Opti...
- silent_cal 3y agoWhy this constant desire in tech to make things more complicated instead of less? It drives me nuts.
- epgui 3y agoThe main source of complexity here comes from the design of the python language. The ideas this library is based on actually come from languages that seek absolute mathematical simplicity. Don't let unfamiliarity get in the way!
- silent_cal 3y agoThis doesn't make any sense to me.
- epgui 3y agoWhich part?
- emblaegh 3y agoWhat if it is not actually more complicated, but just contains concepts and patterns you haven't learned yet or are not used to? All this library offers is a way of composing functions, the kinda stuff that comes default in many languages.
- silent_cal 3y agoNot sure what this means. You can write whatever kind of function you want in Python in a very readable way.
- emblaegh 3y agoMy point is that the sample code is pretty readable, it just involves patterns and jargon from other languages that Python users might not be used to.
- 3y ago
- epgui 3y agoI don't really disagree with other commenters saying that there are easier ways to read and write code in Python... However: - I think the response is excessively negative, there are some really great patterns in here - I put most of the blame on the ugly "design" of the python language (and a lack of guardrails which takes away a lot of the value a library like this would otherwise provide) - I can easily imagine this library, or an interface similar to it, being used on a large code base in a production/commercial setting. I think people who can't imagine that probably just don't have a lot of imagination.
- emblaegh 3y agoPeople in this thread seem to be conflating "it's less readable" with "it's written in a dialect I'm not used to". The samples are perfectly readable to anyone who spent some time with a languages that offers similar functionality, other criticisms notwithstanding.
- epgui 3y agoTotally agreed. Simplicity =/= familiarity
- BerislavLopac 3y ago> People in this thread seem to be conflating "it's less readable" with "it's written in a dialect I'm not used to". I have long been arguing that this is exactly what "readability" means. Readability is completely subjective, and depends on personal experience with various languages, types of syntax and so on.
- epgui 3y agoI am okay with your definition of "readability", but only insofar as you use it to criticize the reader. Code should be judged on its own merit, and in that case your definition of "readability" doesn't really help us go anywhere.
- emblaegh 3y agoCode readability can’t be judged unless you consider to whom it’s meant to be readable.
- bradrn 3y agoI use Haskell as my main language. I’m very familiar with its concepts. I’ve also used Python, so I’m familiar with that too. And this Python code strikes me as singularly unreadable, both compared to its ‘non-functional’ equivalent, and to the corresponding Haskell.
- rkangel 3y agoYes, but now you are requiring people to know both Python AND Haskell/StandardML/Whatever in order to maintain your Python app. Python is not just a "base" language, it's also a set of patterns for how you go about writing code in it. Conforming to those patterns to some degree makes for (subjectively) nice code, and (objectively) easier to understand code because of the familiarity.
- darkest_ruby 3y agoPython is just not made for FP, so any addition of FP into python makes it look even worse
- languagehacker 3y agoAh great, I've been trying to make my Python look more like Scala! In all honesty, Return's docs call out how problematic if-else chaining is, and then proceeds to replace it with chained lambdas. How is that better? I'd go as far as to say that we can avoid a lot of the null coercion stuff with proper encapsulation, but that is basically saying, "We can solve Python's FP challenges with better object design," and I understand how that may sound like nails on a chalkboard to some. If this helps you write the kind of code you and your peers want and can understand, who am I to judge?