4 ms·
> I also noticed there is a tendency in lispy languages to avoid introducing variable bindings just for the sake of naming the subexpression, because it often c
by zelphirkalt 6y ago
> I also noticed there is a tendency in lispy languages to avoid introducing variable bindings just for the sake of naming the subexpression, because it often comes with a `(let ((name (subexpression))) rest-of-code)`, which also results in extra tabulation for the rest of the body. Compare with variable introduction in languages like python/js/c++/rust, etc., where such thing wouldn't cause touching the rest of the function/clause. I guess it's more of a 'functional language' artifact, e.g. in Haskell you'd probably have a similar issue.
I have found myself thinking about "Should I really introduce another let form for naming these things I am going to use at the next procedure call, to make it more readable? Or would it make the code less readable, because of the additional indent?". So there is something to this point. Right now, while not writing code, I would say:
The indentation make the scope of the bindings clear. It tells you exactly, until where a binding will be defined. It also allows you to shadow a binding from an outer scope for the purpose of using it in the inner scope. However shadowing should be used with care, because it can also get in the way of readability, if used wrongly. It can however also increase readability, if used well.
In a language like Python, you can only write things at the same level of indentation. It does not make it clear until where these bindings might possibly be used. The scopes are not as separated as in Lispy languages with the let form. That inherently makes it not as readable, I think. "The rest of the function" is not a very precise scope specification. Many bindings might only be used for one or a few subexpressions and not everywhere until the function ends. This only makes sense though, if the code has side effects. Otherwise there will be no difference in where the bindings still exist, because what in Python is the rest of the "function", will be the inner parts of the expression of a procedure in Lispy languages.
I have found myself looking for a thing like let in Python though. I have sometimes thought: "Hey, can't I use a with-block for making a temporary binding?", but that has never worked for me, because I think you need to make a context manager for that? It has never materialized in my style of Python code. (I know Hy, but until it can offer me TCO and lambdas and let forms like Scheme, I am not sure I would like to use it.)
EDIT: Ah and not to forget about let* which can often reduce the amount of indentation a lot. Sometimes I find it good to make use of it.
- Abhinav2000 6y agoWhen would shadow binding help create more readable code? (I agree with everything else in your post)
- zelphirkalt 6y agoI think it would do that, if in the inner scope, you only need a part of something from the outer scope. Lets say you have a list of things and they have the name according to what they are, lets use "things" as a placeholder. Then in the inner scope, you are still working with "things", just not all of the outer scope, but for reading the code of the inner scope, it does not matter. You are still working with "things". OK, this is quite abstract. I am thinking about it in something like nested named lets, where you make a functional update to something, that comes from the outer named let, inside the inner named let and then use it as an argument to a procedure call. Situations like that. And perhaps only, when it is difficult to name this subset of things anything else than the original name. If there is easily available another fitting name, then I would always go for that. It does make renaming things harder though.
- dmohs 6y agoYes it does make renaming harder, but if your compiler warns about unused variables it might save you more often than not.
- Abhinav2000 6y agoThanks
- spacemanmatt 6y agoI just stop myself when I detect tab-driven development. Readability and function have to trump aesthetic concerns about indentation level.
- bjoli 6y agoIn some schemes, you can have defines also in expression context. You can even add it by redefining a couple of standard forms. Our scheme of choice, guile, introduced it in guile 3.