This is certainly a valid criticism of TADS. It can lead to messy code. The first-approximation answer, of course, is that you should put it in the troll, because it’s a special condition that only comes into play when the troll is present. But there might be five or six different weird things that can happen when you unlock the chest, in which case putting the code in the chest would be the right approach, as you can consolidate all of those weird things in one code block.
A related but more general situation that can trip up a TADS author is that with a two-object action (such as UNLOCK CHEST WITH KEY), there are always two code blocks – the dobjFor(Unlock) in the chest object and the iobjFor(Unlock) in the key object. If you’re not careful, you can cause duplicated things to happen because you wrote them into both code blocks. Again, this doesn’t happen in Inform, because there’s only one rule that applies to that command … unless you do something weird, I suppose.
That may be a question an author frequently has to ask oneself, but it’s also not the only way of handling things. Almighty “insteads” like that could be defined in the Thing class from which all meaningful parts of the game descend; or a statement could be added to multiple possible methods in the parse/execute cycle; or the situation could be caught and handled in a player’s beforeAction/afterAction; or a constantly running monitor Daemon could handle certain things of that nature… I’m just saying that without a greater understanding of how Dialog works, it kind of sounds like a difference of syntax rather than the ability to do something fundamentally different…
Sure; in the end, TADS and Dialog and Inform don’t do anything fundamentally different from what C can do (or a Turing machine hooked up to a teletype can do). But the experience for the user can be very different!
That’s right. However, Doers simply add one more option to a tricky scenario like having the troll observe the player’s use of the magic key to open the chest. Now we can put the troll’s reaction in the troll object, in the player object, in the key object, in the chest object, or in a Doer. Yikes!
Another thing I’ve noticed with Doers (I’ve never discussed this with Eric, and I could be wrong) is that they respond to the exact command that’s typed, not necessarily to the action if the player uses some other vocabulary that the action itself allows. I’ve never exactly worked out in my own mind how to use Doers, so I generally avoid them.
I admittedly only have a beginner’s understanding of these things, but don’t adv3Lite’s Doers solve this issue? They work like Instead rules, where you can just specify a behavior that applies to an action under an arbitrary set of objects and conditions.
I agree though that this problem is probably the biggest issue with TADS’ approach as opposed to Informs. It sort of seems to stem from the classic Object Oriented Programming issue that Steve Yegge talked about where you not only represent nouns as objects, but you try to nounify actions — instead of representing verbs as discrete things with all their behavior on the action, since the action is what’s actually doing things, you try to make actions into objects by sprinkling their implementation all over the class hierarchy.
Edit: I see this has already been addressed. IMHO having more options isn’t a bad thing as long as in every case you have a good option.
It seems to me a person can put whatever conditions/overrides/insteads they want in something like the execAction method of an Action, before the normal handling is sent to dobjFor or iobjFor of a noun @alexispurslane , unless I don’t get what you’re meaning…
But agreed that the variety of options for solving the problem doesn’t seem to me a bad thing…
That’s very useful information for sure, but I was making a more general point about software engineering and architecture:
The decision to make putting the logic for carrying actions out on the objects of those actions the first resort, and leave actually putting that logic on the action itself to a secondary approach which isn’t as flexible/extensible/succinct, is a common design pitfall in highly object oriented systems.
It can cause exactly this sort of code organization issue to arise, where there’s a question of where to put things and thus the possibility of inconsistency and accidental complexity and so on. Now there are far more places to handle possible actions than if everything was on the action itself, and that can lead to problems.
This tends to stem from thinking in terms of the Nouns involved in programming first, and the verbs only incidentally. Not falling for this, and instead applying the poweful concept of Prolog-style rules, where the most specific rule applies first and you can dynamically add edge cases, seems to be Inform’s primary selling-point to me. This is the difference between the OO paradigm of TADS and the declarative paradigm of Inform 7 I was talking about.
Does that mean one is better than the other? Hardly. But I do think this is where the fundamental allure of Inform 7 stems from. It’s a very different view of game systems that, intentionally or not, seems directly in answer to much of what has been learned in the last twenty years of software development in the wider industry. For me, TADS is so much better than Inform in enough other ways that this alone isn’t enough to make me use Inform, but it’s interesting.
I have not used it but read about it when it came out. I think one of the advantages was non-English-language coding that appealed to those who hate I7-10. I also got the feeling that Linus was very cognizant of giving it similar functionality to Inform 7 since Inform does most everything you’d want to create in an “Infocom-style” parser adventure. It seemed most things you’d want to do had a direct equivalent in Dialog.
Dialog also supports clickable links out of the box, and with some clever programming, an author can make a game almost entirely mouse-driven, so it seems it could be a solution to create a mobile parser game.
Yeah, it is very much a response to Inform 7 in its design—it’s taken a lot of lessons from what worked and what didn’t in I7, and also started from scratch instead of adapting the venerable Inform parser.
I still use I7 because I like its natural-language style, but Dialog is a close competitor for my favorite system.
I’m really not trying to be antagonistic! I just haven’t gotten it yet… if you have roughly four thousand sim objects in your game, why would you want to handle at least several hundred object-specific cases “in the action”? Just a huge nest of if statements or specificity rules under each verb? Where is the drawback to putting all the default behavior in Thing.dobjFor(Verb), even referencing a few edge cases in that block if desired, and putting object-specific reactions in object code, with still the option to incorporate a trump-the-whole-normal-process set of statements for a finite number of specialized cases? (Where intransitive verb behavior can defined with its custom conditions under the verb, with the option for Rooms to override the handling when the verb is used there.)
I still don’t really understand how Inform differs from this in such a way as to make it a standout selling point… I’m actually trying to understand the difference…
It’s a valid question. I don’t have a complete answer, because I’m not an Inform expert. However, the thing that has always worried me about Inform 7 is that the compiler constructs the various action rulebooks at compile-time. It does this in defined ways, putting more specific rules earlier in the rulebook and more general rules later – but the ordering of the rules is, frankly, opaque. You can specify details in your code, putting your new rule first or last, or before some other specific rule, but you never get to inspect the rulebook and make sure the compiler got it right.
In TADS, on the other hand, if you’re writing code for the entire Thing class (the most general level of the action), when you write Thing.dobjFor(SomeAction), you get to list the various parts of the code in whatever order you feel is needed. This is more work for the author, but the benefit is, you get to do it yourself. You don’t have to spoon-feed the compiler in the hope that it will turn out okay. And when you write code for MyGameObject.dobjFor(SomeAction), you are absolutely guaranteed that it will be consulted instead of the code for the same action in the Thing base-class.
For me, I had a literal “aha, this is how you ride a bike” moment because I was really concerned at first with “how will Inform know what order I want my rules to run/compile in” and the answer is “You don’t really need to worry about that.” It doesn’t usually matter because you prioritize rules by specificity instead of code-order. And since it reads your source top-down, any rules you’ve written by default are dropped on top of a rulebook stack and thus take slight priority over the Standard Rules that are there.
I mean, this is probably why it drives coders crazy because you’re not really in charge and you sometimes make it work with finagling!
So first I should clarify that when I’m talking about action logic being in “one location” “on the action” what I mean is a sort of conceptual association and location in the control flow, a logical location,/not physical location in your text file. Think about the difference between logical discs and physical discs in operating systems.
Second, there are two big differences that make this so important:
In TADS, because it is primarily oriented towards deciding what happens when you take an action on objects, and then offers several secondary methods of deciding actions in other places, the control flow for deciding what happens when you take an action is orders of magnitude more complex than a rulebook, where it just chooses the most specific rule at one precise place in the control flow of the world simulation. So it introduces a lot of accidental complexity and possible confusion. Lots of edge cases and places to check and things that can cause “spooky action at a distance” and lots of design choices as to where to put things.
Even more importantly, even though it is indeed possible to put all of the logic for an action in one location in the control flow in TADS, because doing so is a second class citizen, it will be a lot more awkward and less extensible and flexible and natural to use — as you pointed out with your incredulity that a giant list of if else statements would actually be superior. The crucial point in inform it’s not a giant list of if else statements; it’s represented internally like that, but you can define those conditions anywhere in the code that makes the most sense to do so, and they’re all assembled to gather by the compiler, so it’s much more flexible and ergonomic to use.
Regarding Dialog, it’s got one feature that both TADS3 and Inform 7 lack, and that is REPL coding. If you use dgdebug, you can develop on the fly without recompiling all that often (if you do need to recompile, dgdebug will tell you).
Dialog’s other strengths include a succinct and unsurprising standard library (no hidden precompiled behaviour or hackiness), very clever handling of “it” when it comes to disambiguation, a simple and intuitive way of printing object names, “thin” objects that are collections of behaviour more than state, an elegant approach to lighting, scope, reach, granular masses, handling identical objects and group actions. It’s quite frugal in terms of performance and memory footprint too, being designed as a means of running Inform 7 style code on the C64.
It’s shortcomings so far are slow adoption, lack of significant graphical facilities (though this appears to be planned for future releases), a small userbase (i.e. less opportunity to learn by osmosis) and the fact that most coders don’t think in Prolog.
Paradoxically, I think the high polish and quality of Linus’ own games for the system may have ended up a barrier to entry, or at least it was to me: when all existing products of a novel paradigm are top-tier offerings, the prospect of being the first mediocrity in Dialog was demotivating.
Still, as you may be able to tell, I’m really impressed with Dialog so far. If it gets graphical support (particularly for retro systems like the Amiga), I personally can’t envision sticking with I7 or TADS.
Me too. I hadn’t really even noticed it up to now, but now I’m thinking, “Hmm, that could be a fun thing to try.”
It has even crossed my mind that I ought, as a sort of “Cloak of Darkness writ large,” to try producing the same game in Inform, T3, and also Dialog, just to observe the differences close up. Now all I have to do is figure out where Dorothy hid the golden cap. This is one of the three or four key puzzles in the story, and until I have the puzzle structure laid out, there’s no point in starting the writing.