Forgive the long preamble, but I think the context is important. It’s been a good few months since shadowing was outlawed and I’ve been trying to follow the shadowing advice for renaming variables. My usual workflow when creating functions is to have a
let..in block at the top. I then go to work in the body of the function. Whenever I have written enough code to think “ah, yes, I can name this!”, I put it into the
let..in area. During the writing of additional parts, I sometimes find that I need to change the earlier code (or even types) and so I modify the
let..in block. Later on, I separate out some of the
let..in block into separate functions. Think of the
let..in area as a place where you can be mutated, promoted to top-level, or killed entirely, depending on how things work out.
This means that when I make functions in the
let..in section, I am often working with related data. Right now, I’m doing something with “properties” (which mean something domain-specific, don’t get hung up on the name), so I pass in something to the top-level function and name it
prop. Now I have the following pain point: I can’t use
prop anywhere else. As a result, I’ve got all sorts of rubbish names:
p, and so on. Could I choose better names? Well, yes. One can always choose better names. Could I choose better names, while still staying in the flow of what I’m doing and not losing track of the overall objective of the code? Experience has shown me that the answer is “no”. If I try to, I lose my focus and my productivity takes a hit. Instead, I have a fixed set of mental prefixes and suffixes that I apply:
this, etc. Maybe I’m not smart enough or not multitasking enough or something, but after months of trying, this is where I’m at. More design would help, but no, I don’t always do a full design to this level of detail up-front; in all honesty, 99.9% of programmers that I know don’t do so either. As it is, I do a lot more design than most.
Annoyingly, once I actually split things out into helper functions, I know that this problem will go away because scopes will change. And then I’ll go through and change
prop_ etc everywhere to
prop, which is the naming convention that it should have been obeying in the first place…
Here are some things that I’ve tried:
Don’t compile the code until it’s in its “finished” form. This has all of the drawbacks of not-compiling-code that I’m sure that you’re aware of and, just like a chef who doesn’t taste their food while it’s being made, it sometimes leads to worse problems.
Split things out into top-level functions early. This is a bit more work and it sometimes breaks my focus. Type signatures are useful things, but with that said, I find it visually distracting to push things to the top-level when I’m not sure that I’ll keep them and when their form isn’t too stable yet.
I’m sure there are other things that I’ve tried, too, but these are the most “solid” solutions that I’ve hit upon. Neither is particularly good.
What also prompts me to write is the fact that I’ve been working in F#, where shadowing is allowed and this issue doesn’t exist at all. Why? Because one presses F12 (“go to definition”), and warps to the point where the identifier is defined. This takes less than half a second and puts you straight into the context of the definition too, which is incredibly useful. So the “tricky shadowing bug” that spurred @evancz to outlaw shadowing entirely can be addressed by having better editor support! That makes me wonder whether this should even be a language-level issue. At most, at this point in my experience, I would say that it should be a linter warning.
Speaking of the shadowing bug, I’ve discovered just how easy it is for one to write
prop instead of
prop_, especially when the two mean almost the same thing. But that’s a story for another day…
In any event, let’s have a discussion. Is anyone else running into this in their day-to-day? What are your solutions? I’m sure that the question of “should shadowing be allowed?” has been explored by @evancz at some other point in time and these issues have probably been raised, so let’s try to keep it to how to practically solve this pain point. What works for you?