5 ms·
After many years in Ruby, I feel strongly that the idea of a block is necessary for optimal expressiveness of a high-level language. Destructors are too implici
by mattgreenrocks 3y ago
After many years in Ruby, I feel strongly that the idea of a block is necessary for optimal expressiveness of a high-level language. Destructors are too implicit and fine for resources, but not as great when understanding code. And Python’s context managers trying to help with exception-safety is a nice touch.
The Lisp crowd was right, as usual.
- baq 3y ago> The Lisp crowd was right, as usual. 40 years ago. Fortunately we’re getting there, feature by feature. Maybe 2030 will be the decade yaml goes away.
- barefeg 3y agoWhat would be the way to do yaml?
- adamfeldman 3y agoCode as data https://news.ycombinator.com/item?id=16398791 https://news.ycombinator.com/item?id=16398791
- rco8786 3y agoYup, came to say this same thing! I read this whole article going “this is easily solved in Ruby/Lisp”
- nerdponx 3y agoA general concept here is of a "context", which both Ruby blocks and Python context managers try to provide. Something happens when you enter the context, your code runs, and then something happens when you exit the context, maybe varying depending on how you exited. Such "contexts" are somewhat ad hoc in Lisp, whereas Ruby and Python have built-in language support and special syntax for them. The traditional Lisp idea is that you don't need special language support when you have macros and higher-order functions, but the special language support also means that all context managers follow the same protocols, whereas ad hoc contexts introduced by CALL-WITH-FOO/WITH-FOO are more like a common loose convention than a standardized system. Functional programmers have also understood this idea of structured contexts for a very long time, giving us Functor, Applicative, and Monad.
- lispm 3y agoOne other way to deal with 'context' in Lisp is for example by the ADVICE mechanism or the method combinations (:around, :before, :after, ...) of CLOS. https://en.wikipedia.org/wiki/Advice_(programming) https://en.wikipedia.org/wiki/Advice_(programming) > all context managers follow the same protocols Lisp is an old language with lots of dialects and systems. Thus people had different needs for context management and different facilities available to implement it.
- LanternLight83 3y ago> Lisp is an old language with lots of dialects and systems. Absolutely, my first thought was `dynamic-wind`. https://www.gnu.org/software/guile/manual/html_node/Dynamic-Wind.html https://www.gnu.org/software/guile/manual/html_node/Dynamic-...
- marcosdumay 3y agoLisp? You don't need to go all the way to Lisp. Declaring data imperatively is quite a contradiction. You need a lot of effort and misguided design to create it. You don't need first class code blocks to avoid it. (But, of course, first class code blocks help in many other ways.)
- whstl 3y agoAnecdotal, of course, but: often the most elegant solutions I see in my job are from programmers coming from Ruby. It is interesting to see how different programming languages can shape our mindset. A big part is those good solutions are those little lambda-receiving functions that do all the heavy lifting without imposing a lot of boilerplate. Not too many of them, of course. IMO this kind of thing is where the “getting things done” and “good architecture” meet.
- akavi 3y agoWhat do blocks give you that good old-fashioned first-class functions don't?
- kstrauser 3y agoFor example, here's how you'd read a file in Python and operate on its contents. with open('file') as myfile: process(myfile.read()) When control leaves that context, `file.close()` is always called. You don't have to remember to close it. Even if `process()` raises an exception, the `with open` context will close it before passing the exception upward. You never have to remember to clean up the file yourself. It's not that you can't do all that without context managers, obviously. People have done it for a long time. It's just that the `with open...` pattern is effectively bulletproof and removes just one more potential footgun.
- akavi 3y agoIn JS, we could do: open('file', (myfile) => process(myfile.read())) It would be on the implementer of `open` to call `file.close()`, but presumably that's true of python as well?
- kstrauser 3y agoI think so, depending on how I'm reading your definition of "the implementer". If you meant "the code that implements the open() context manager", then yes. It looks something like: def open_context_manager(filename): try: f = open(filename) yield f finally: f.close()
- norir 3y agoI agree. The most important feature of a high level programming language is first class closures with lexical scoping. Almost every design pattern, including the IOC in the original article, can be implemented with them (along with a few other core data structures and primitive operators). By contrast, there are many patterns that are very difficult to implement by hand in c because of the lack of first class closure support (c++ of course is a bit better since it has lambdas, but then you have to opt in to everything else in c++).