I went to the Roguelike Celebration over the weekend and enjoyed Thomas Biskup's talk about Ultimate ADOM. Among the many interface improvements they're making based on user testing is they're simplifying the controls from the traditional roguelike controls to W A S D + E F. I don't know how roguelike game players will respond to that but I'm a fan! This reminded me of two things from my past, so I thought I'd say a little about those.
Sometime in my teens I got to meet Lord British (Richard Garriott) and Iolo the Bard (David Watson). My mom was shopping, and I went to the computer aisle to browse the games I couldn't afford. Richard and Iolo were talking about Ultima 6. Nobody else was there, so I got to talk to them for half an hour! I learned about OOP, UI, testing, systems thinking, and more. Really cool!
They told me about how they coded puzzles to look for the state of the world (nouns) instead of the player actions (verbs).
For example, there was a puzzle where they expected players to cast Telekinesis (ᚩᚣᛕ ORT
POR
YLEM
) on a lever on the other side of a chasm. Instead, during playtesting, they saw that one player killed a party member, tossed the body over the chasm, cast Resurrect (ᛁᛗᚳ IN
MANI
CORP
), then have the party member pull the lever.
Wow! That wasn't something I had ever thought of in the simple games I had written at that age.
Another thing they told me about was the simpler control scheme. Previous Ultimas had a control scheme similar to what roguelike games have. W to wear armor, I to ignite a torch, K to klimb a ladder, D to descend a ladder, B to board a ship, etc. You specify the verb such as J to jimmy a lock and then after that you can choose a noun such as the lock to jimmy.
In Ultima 6 they reversed the order so that the noun came first and then the verb. This meant the game could tell whether you were trying to J jimmy a lock or B board a ship or K klimb a ladder because the game knew that it was a lock or a ship or a ladder. And that meant they didn't need separate keys for these verbs, but instead one key, U use object. There are times when they had multiple verbs for a noun but for the most part they could get away with just one.
I haven't closely followed Ultimate ADOM but I'm guessing they're doing something similar.
The noun-verb thing comes up in another context. After I stopped making games for a living I went into programming language research. My main topic was studying how functional programming languages and object-oriented programming languages can be combined.
Something I noticed at the time was that the syntax for functional languages tends to be verb then noun: f(x)
, whereas the syntax for object oriented languages tends to be noun then verb: x.f()
.
At some level these can be considered equivalent. You can express with one what you can express with the other. There's a big difference in usability though: auto-complete.
What happens when we auto-complete f(x)
? First we need to know all possible f
that are valid in this context. Since the programmer has just started typing in the expression, any function is valid, and that means there's a very long list to choose from. It takes many keystrokes to pick one. Second we need to know all possible x
that are valid in this context. These are usually local names, so there aren't that many. Knowing the type of f
narrows down the list but the list was already small, so there's not much to gain.
What happens when we auto-complete x.f()
? First we need to know all possible x
. The programmer has just started typing, so any local name is valid, but there aren't many. Typing just one character can narrow down the list to one or two elements. Second we need to know all possible f
that are valid in this context. These are methods defined on the type of x
, so there aren't that many compared to all possible functions. Knowing the type of x
narrows down the list substantially, so there's a lot gained.
The two syntaxes seem equivalent in theory but they aren't in practice. I wonder if people who use regular text editors end up believing the two syntaxes are equivalent, whereas people who use IDEs prefer the object-oriented syntax, even if they're not taking advantage of object-oriented programming (inheritance, subtyping, etc.).
This asymmetry is orthogonal to whether you're using functional or object-oriented programming. It is better for programmers if they can choose from two medium length lists than to have to choose from a very long list (where a lot has to be typed before it's useful) and then a very short list (where not much is gained).
You see this in other contexts too. Command line interfaces like DOS, VMS, and Unix shell typically specify a verb first and then the noun(s). GUIs such as Mac and Windows typically specify a noun first by clicking an icon, and then the verb by choosing from the right click menu. In text editors, vim's commands like d0
are verb then text selection (noun), whereas in more conventional text editors (including Emacs) you'd first select some text (the noun) and then invoke a verb like delete. Kakoune is a modal editor that uses noun-verb instead of verb-noun.
In games it seems like it'd be better for players to first choose an object from the environment and then choose from a small set of actions, than to first choose from a large set of actions and then choose from a set of objects. However I haven't surveyed enough games to see what's more common. The next time you're playing a game, look at the structure of commands to see if it's verb-noun or noun-verb.
[Update, 2020-09-27] Ordering also matters for type inference and compiler error messages, as shown in this post from Javier Chávarri.
[Update, 2022-06-11] There's an Emacs package called Embark that uses noun-verb ordering.
Labels: structure
Really interesting points. To add some nuance: vim does support noun-verb order, using `v` to make a visual selection before acting on it, but it's not the way vim is usually taught (or, I believe, used). And it's at least one more keystroke.
SQL has the same problem with autocomplete because of its verb (SELECT) noun (FROM) ordering. This is why the C# team decided on the reverse for LINQ. The SQL case is especially baffling because it also does not reflect execution order, nor the order in which people naturally think about a query, nor was it needed for getting something resembling English.
@Thomas: true, visual mode is noun-verb but as you say, it's not the usual approach. I did try forcing myself to use visual mode for a while before realizing it's just going against the vim grain. :-)
SQL ordering is frustrating. I think the only justification for SELECT coming first is that seeing the list of columns doubles as a "type declaration" of the output. But I wish it were more like a pipeline. LINQ is awesome and I wish more languages had that.
See also: https://cosine.blue/2019-09-06-kakoune.html
One such narrowing tool seen in functional languages is to explicitly leverage modules. In the current generation of languages, this can be seen in Clojure/Lisp (namespace/function), or Elixir (Enum.map). While it's not as explicitly correlated with type, there's usually a type implied or closely associated with a given module's functions.
Liked this! Congrats on your posting to HackerNews.
I think the point extends well to HTTP's design, since it is explicitly VERB NOUN (e.g. GET /index.html HTTP/1.1)
The reason it works there is the VERB list is explicitly narrow (effectively 4, though I suppose we're up to 6+ now)
Thanks for your insights.
That is an interesting point.
I think i still prefer verb/noun, as it can make the code easier to read and (hopefully?) easier to maintain.
The vast majority of the time spent in code is not creating it, it is usually changing/understanding/refactoring it.
For me, it's all about making the code as clear and as close to naturally read english (or your prefered language) as possible.
There is a compromise: pipes. I have found myself using them many times in Elm, because they make the code so much more readable. Now I understand why!
It looks like this:
noun
|> verb1
|> verb2
|> etc
I haven't seen an autocomplete that works on pipes. But with a good type system, it is technically possible to list all compatible functions that take "noun" as first parameter.
Sometimes you supply partially applied functions (also with pipes in noun->verb order) and that's not so easy to match:
noun
|> verb1
|> (otherNoun >> verb2)
|> etc
But perhaps even functions that take "noun" as nth parameter could be suggested.
Thanks for your wonderful words! We appreciate the shout out. I just want to clarify how Ultimate ADOM does it, because we're actually going a step further. At the risk of Thomas coming in and contradicting my every point, I will nevertheless simplify:
We still work in a verb->noun fashion, only all nouns are basically the same, only with different properties.
The wonderful Lever example (which I remember - I was trying to shoot it and throw things at it and despaired that I couldn't) would look like this in Ultimate ADOM:
The lever only knows it's an object that's stationary and can be flipped. It's probably also made out of some kind of material.
So in Ultimate ADOM, you would be able to flip the switch by interacting with it. Or hitting it with a melee weapon. Or throwing something at it. Or hitting it with a spell. Or animating the lever to turn it into a golem and have it attack a monster, thereby flipping itself. Or melt the metal in an acid pool, thereby never flipping the lever ever again.
Ultimate ADOM's design thrives on such decisions, and we intend to make use of it in several dedicated puzzles, as well as randomly generated shennanigans.
Hope that provides a bit more insight - and thanks again for mentioning us! :)
I am not sure what point are you making with the Resurrect example? This reminds me of one RPG with similar puzzles, where for one level AFAIK the only solution was to kill all party members except one, drop their bodies in correct spots, and then resurrect them.
In Haskell you can write: 2 & sin (easy to find by type)
A similar function/operator is easy to write in other functional languages. Probably does not help with auto-completion though, as lots of functions can be applied to everything.
LucasArts adventure games made a similar change. With the exception of Loom all pre-1995 scumm games required the player to click the verb first and then the object to apply the verb to. Full Throttle was the first one where you would click and hold the object to show a pie menu with available verbs. Later games used a "use" key or default action when selecting an object. Leading up to the change, some of the earlier games already highlighted a default action when you pointed at an object which could be selected without explicitly selecting the verb first, although selecting the verb first was still required if you wanted to apply a different verb.
For autocompletion, I think the important part is not simply the order, but the presence of a scope.
Sometimes the subject(noun) can act as a scope, especially if it is a custom type with few methods. But some types will have lots of methods, or lots of both language-included and user-defined functions defined on them, so the type-based scoping is not really that useful. You'd want to specify a more limited scope, like a module, or some other type of namespace.
Namespaces are the key, languages should always offer first-class support for easily creating arbitrary namespaces. Classes can be namespaces, but they are tied to a type, and they may involve unwanted overhead. Modules are often file-based, so you can't use them as much as you could want.
Post a Comment