On Thu, Jan 17, 2019 at 05:32:52PM -0800, Walter Bright via Digitalmars-d-announce wrote: > On 1/17/2019 11:31 AM, H. S. Teoh wrote: > > [...] > > Thanks for the thoughtful and well-written piece. > > But there is a counterpoint: symmetry in mathematics is one thing, but > symmetry in human intuition is not. Anytime one is dealing in human > interfaces, one runs into this. I certainly did with the way imports > worked in D. The lookups worked exactly the same for any sort of > symbol lookup. I thought it was great. > > But I was unable to explain it to others. Nobody could understand it > when I said imported symbol lookup worked exactly like any lookup in a > name space. They universally said it was "unintuitive", filed bug > reports, etc. Eventually, I had to give it up. Now import lookup > follows special different rules, people are happy, and I learned > (again) that symmetry doesn't always produce the best outcomes.
Alas, it's true, it's true, 100% symmetry is, in the general case, impossible to achieve. If we wanted 100% mathematical symmetry, one could argue lambda calculus is the best programming language ever, because it's Turing complete, the syntax is completely uniform with no quirky exceptions, and the semantics are very clearly defined with no ambiguity anywhere. Unfortunately, these very characteristics are also what makes lambda calculus impossible to work with for anything but the most trivial of programs. It's completely unmaintainable, extremely hard to read, and has non-trivial semantics that vary wildly from the smallest changes to the code. For a human-friendly programming language, any symmetry must necessarily be based on human expectations. Unfortunately, as you learned, human intuition varies from person to person, and indeed, is often inconsistent even with the same person, so trying to maximise symmetry in a way that doesn't become "counterintuitive" is a pretty tall order. As somebody (perhaps you) said once, in Boeing's experience with designing intuitive UIs, they discovered that what people consider "intuitive" is partly colored by their experience, and their experience is in turn shaped by the UIs they interact with. So it's a feedback loop, which means what's "intuitive" is not some static set of rules (even allowing for arbitrarily complex rules), but it's a *moving target*, the hardest thing to design for. What's considered "intuitive" today may be considered "totally counter-intuitive" 10 years from now. In the case of imports, I'd argue that the problem is with how people understand the word "import". From a compiler's POV, the simplest, most straightforward (and most symmetric!) definition is "pull in the symbols into the local scope". Unfortunately, that's not the understanding most programmers have. Perhaps in an older, bygone era people might have been more open to that sort of definition, but in this day and age of encapsulation and modularity, "pull in symbols into the local scope" does not adequately capture people's expectations: it violates encapsulation, in the following sense: symbols from the imported module shadow local symbols, which goes against the expectation that the local module is an encapsulated thing, inviolate from outside interference. It breaks the expectation of encapsulation. It breaks the symmetry that everywhere else, outside code cannot interfere with local symbols. Consequently, the expectation is that imported symbols are somehow "second class" relative to local symbols -- imported symbols don't shadow local symbols (unless you explicitly ask for it), and thus encapsulation is preserved (in some sense). So we have here a conflict between different axes of symmetry: the symmetry of every module being an inviolate, self-contained unit (encapsulation), and the symmetry of having the same rules for symbol lookup no matter where the symbol came from. It's a toss-up which axis of symmetry one should strive for, and which one should be compromised. I'd say the general principle ought to be that the higher-level symmetry (encapsulation of modules) should override the lower-level symmetry (the mechanics of symbol lookup). But this is easy to say because hindsight is 20/20; it's not so simple at the time of decision-making because it's not obvious which symmetries are in effect and what their relative importance should be. And there's always the bugbear that symmetry from the implementor's (compiler writer's) POV does not necessarily translate to symmetry from the user's (language user's) POV. Still, I'd say that in a general sense, symmetry ought to be a relatively high priority as far as designing language features or adding/changing features are concerned. Adding a new feature with little regard for how it interacts with existing features, what new corner cases it might introduce, etc., is generally a bad idea. Striving for maximal symmetry should at least give you a ballpark idea for where things should be headed, even if working out the details is generally not so straightforward. It may be that you will discover mutually-exclusive symmetries that, no matter which way you take, will lead to trouble later on. Conflicts of this sort usually cannot be fully resolved without essentially gutting the entire system to the core and rebuilding from scratch, which usually is not a practical thing to do. So we're stuck with imperfection. Nevertheless, IMO we should still strive for perfection, even if it's ultimately unattainable. Being slightly closer to perfection is better than being far off. > User interfaces (and programming languages certainly are user > interfaces) are hard and (ironically) are anything but intuitive to > design. Yes, it's very unintuitive to design intuitive interfaces. :-D It's the paradox of user-interface design. T -- Life is too short to run proprietary software. -- Bdale Garbee