23 ms·
Variable names are a good thing. When I look at someone else's code (or my own, 6 months later) I do not want to see @1, @2, @3, and so forth. I don't care if i
by intertextuality 8y ago
Variable names are a good thing. When I look at someone else's code (or my own, 6 months later) I do not want to see @1, @2, @3, and so forth. I don't care if it's some existing mathematical notation concept or not, we're not discussing lambda calculus here.
Naming things properly is a skill we all need to have as programmers. There are (multiple) reasons we don't call things k, d, j, z, o all over the place anymore.
And for the record, I actually prefer λx. λy. x instead of λ λ 2. We do not need to be as terse as possible when writing programs or mathematical statements. This is especially egregious for Ruby, a language that has been valued for being quote, "elegant".
- yebyen 8y agoYou know, naming things is hard, and it's not reasonable to argue that your code should always be in the optimal state. There are "on the way" states, and it seems like this feature can be used well by saving you from choosing a wrong name too early in the development stages. Sometimes you haven't decided what a name should be yet. I do not want to see @1 @2 @3 in code 6 months later, either. That's the kind of thing that I'd search for in my codebase before I closed the project, and assign a name before it's too late for me to remember what that bit of code was for. (And look, how handy it's a completely original arrangement of characters that you can even grep for without straining!) But sometimes you don't have a name ready and it's actually better to defer naming the thing until you know what it is. This feature enables that. You can save yourself from picking a wrong name, come back later when the code around that @# has solidified and it's clearer what to call it. I have never seen this feature before this article, but seeing the ways that people are arguing against it has given me a better understanding of the ways that it can be used well. I've just been catching up on my tech lore and I'm watching Sandi Metz talks from RailsConfs gone by. There's one talk in particular "all the little things" where the subject is the gilded rose exercise, and how she would refactor it. In the course of the exercise the code complexity goes up (almost doubles) before the gains are realized, and suddenly there's this huge bit of code that can be safely deleted, now the complexity has gone way down and the code is good. My only point in bringing this up is that there are intermediary states that, if observed in a vacuum, we'd all agree are badly formed and simply not exemplary. This strikes me as an example of one of those features. You can come back and make it better. This is just how it will look "on the way" to something better. (I know, "you won't come back" but that's not an argument that I'm ready to accept.)
- intertextuality 8y ago> it's not reasonable to argue that your code should always be in the optimal state. This is a strawman and not what I believe. I never said your codebase should always be optimal in every way. I believe @1 instead of even the most basic of variable names is actively an anti-pattern. > That's the kind of thing that I'd search for in my codebase before I closed the project, and assign a name before it's too late for me to remember what that bit of code was for. Maybe you might, but plenty of other people will not. I have also lied to myself and added "TODO" comments in some small projects I've worked on. Months and years later I sometimes see "TODO" comments because I ended up working on something else or forgot. It's simply way too easy to not go back and refactor or fix things. There is nothing more permanent than temporary code. Sometimes you have to go back and rename things multiple times. This is vastly better than what you know full well will happen: People will immediately gravitate towards the easiest option of @1, and then never change it because they've moved onto other parts of the code or different projects, etc. We should not be adding ugly, terse syntax to programming languages because it's "just more convenient" to not name things. That is not a tenable argument for a permanent change to a mature language. Being lazy is not an argument.
- yebyen 8y ago> Maybe you might, but plenty of other people will not. I have also lied to myself and added "TODO" comments in some small projects I've worked on. So it was cheaper to leave the TODOs in the perfectly OK code, sounds like you dodged a bullet there. This strikes me as a slippery slope. Start with "@1 is not an appropriate way to represent this variable" then move onto "I actually don't like the name you've chosen" and finally arrive at "this code isn't important enough for me to take care of those TODOs I placed before I'm old and gray, remind me why are we even worried about how this variable is called, now renaming it for the _third time_?" I'll usually take a collection of "xs" and iterate over each "x" without any pretense that I'm coming back to make it better. We can agree to disagree, but I'm arguing that it's not any better to do that, and it's actually harder to grep for which makes it actively worse. This is a better option.
- 8y ago
- derefr 8y agoHere's something I write all the time in Elixir: a = some_list_of_tuples() |> Enum.map(&elem(&1, 1)) |> # more pipeline here The alternative, without De Brujin indices, is: a = some_list_of_tuples() |> Enum.map(fn x -> elem(x, 1) end) |> # more pipeline here Are you going to tell me that the second example is more readable? Personally, I find that the tiny little elem/2 expression gets lost in the line noise of the closure syntax. Reducing that syntax using an "anonymous closure" like in the first example makes it clearer to me what's going on. And, as well, in such closures, there really is no "name" for the thing that I'm processing. It's an intermediate in a destructuring expression that I'm only holding onto in order to further rip it apart. (The output has a name, say, `foo`; but if the input is just, say, `{:ok, foo}`... then what is the name of said tuple? `result`? `maybe_foo`?) Whatever name you make up there, it would only distract a future reader by making them think that it might be something important to the domain. Oh, and also, at least in Elixir, De Brujin anonymous closures "flow well" with function handles: &List.first/1 # function handle &List.first(&1) # equivalent anonymous closure --- But to put a finer point on it, in practice, 99% of the use I get out of (De Brujin) anonymous closures is just using them as "function handles but with the parameters reordered"—i.e. as a way of wrapping a closure in a combinator, without having to remember the names of combinators. Instead, with De Brujin indices, such "combinator" effects are self-evident descriptions. Elixir code: &(x.(&2, &1)) What is that? An expression that returns a version of the closure x (of arity 2) where the two input parameters are swapped. In other words, that's the C (cardinal) combinator, or the Haskell function `flip`. Except you don't need a special name for it; you just describe the effect you want then and there. Anyone who reads it can see what it does. Is the non-De-Brujin equivalent any clearer? fn a, b -> x.(b, a) end &1 and &2 are metasyntactic variables. a and b here are also metasyntactic variables. There might be a better name for what they are, but frequently there isn't, if this code is e.g. sitting in a library that does something generic with a data structure or algorithm, rather than something specific with business logic. Personally, if I'm going to be using metasyntactic variables anyway, I prefer to use ones that look different in a way that highlights them as metasyntactic variables. Just like I prefer languages that require some sigil on class-instance variables in a method to differentiate them from lexical variables. It allows both regular syntax highlighting, and the "syntax highlighter in my brain", to work more efficiently.