Good coding style in Inform 7

Though if you’re planning to release the source code as a web page when you’re done, the section/heading numbers can be useful then.

Here’s a few things I consider good style for extensions specifically:

  • Use lots of small sections. This makes it easier for a user to replace part of the extension. Otherwise, the user might have to copy and paste a whole chapter just to change one line.
  • In Inform 6 templates, use @p markers for the same reason.
  • Name all rules, e.g. Instead of examining a gorgon (this is the don’t turn yourself into stone rule):.
  • Name all phrases which a user might want to pass to the functional programming phrases. (The reason not to do this for all phrases is that it can make the story file bigger unnecessarily.)

Good point. I’ve also run into a situation where the “Include Extension Name by Author Name” lines weren’t in any section at all, and I needed to change one of them (because of making changes to another extension), and it was impossible to do it without editing the extension directly.

I assume this is the sort of thing talked about in 22.3., for example

To decide what number is double (N - a number) (this is doubling): 

but I haven’t grasped in what context it’d be useful for the story author to be able to say “doubling applied to N” instead of just saying “double N”.

On an unrelated note, I hope properties are better than global variables, because I’ve been trying to get rid of global variables where I can, and most times the only substitute I can think of is to make it belong to a particular object instead of leaving it “free-floating”.

If you want to put the phrase into a table, or store it in a variable or property, it has to be named.

No real difference except as how it lets you organize your code.

(Okay, one difference: boolean properties are tidier than boolean global variables. You can say “The sponge can be moist or dry”, which gives you cleaner code than “The sponge-moistness is a truth state that varies.”)

1 Like

And I consider “the sponge-moistness is a truth state that varies” to be poor style. I think as a rule you should avoid global variables unless not using them is very circuitous. Especially now that i7 supports constants.

So would you say “The sponge can be moist or dry” is a good alternative, or is it not much better than a global variable? What about “The phone has some text called the user-defined password” as an alternative to “The user-defined password for the phone is some text that varies”?

I ask because, if there’s an extension where story authors have to be able to set an option somewhere in their code, and then that option is used by the extension to make decisions (but not necessarily immediately), I’m not sure what alternatives there are to global variables besides properties. I’m not saying there aren’t alternatives, just that I don’t know what they are, or even why, for instance, making a property belong to an object might be safer than its global equivalent. My understanding is that globals are discouraged because it’s too easy for other code to change them and mess them up, but to me it seems just as easy to change the property “the user-defined password of the phone” as to change the global “the user-defined password for the phone.”

1 Like

Hmm, interesting. Thanks.

1 Like

Hm. So, there’s a lot of history there.

In the world of general programming, global variables are discouraged for a lot of reasons, not all of them current or well-supported.

  • A lot of people (including me!) got started in BASIC, where there were only global variables. We had to be kicked into using anything else.

  • When you use a global variable, you’re assuming you’re never going to have two of them. That is: if you have a global for “screen width”, that will work fine until you try to expand your system to support two screens at once. (Whether that means “dual monitors” or “two people logged in via telnet”.)

  • If you like globals, but your program gets large and complicated, you wind up with a giant block of globals; it’s hard to keep track of what goes with what. It’s nice to be able to think of your variables in related groups. (This is what you are getting at when you say “it’s too easy for other code to change them and mess them up”. It’s not that you want to forbid that sort of thing. Rather, you want a program structure where you notice if you accidentally trip across the group boundary.)

  • Namespacing: a large program is probably written by several people, or even several teams of people. If three different people try to invent a global variable called WIDTH, with no way to distinguish, there’s gonna be trouble.

  • For a while, everybody was really excited about object-oriented programming. OO solves the “you need two of them” problem by letting you associate a variable with an object, and you can always make more objects. It also gives you a great way to group variables together, and probably a namespacing system. So there was an era in which, if you weren’t being as OO as possible, you were some kind of pitiable knuckle-dragging relic. (Happily that era is over and people have mostly recognized that Java went too far in forbidding globals.)

Now IF programming is pretty far away from general programming. The fact is that nearly every symbol in an Inform game is global in scope. All objects are global constants; tables are global arrays; etc. It is also true that any piece of code must be able to tweak any variable, anywhere in the game. (Sometimes picking up an old boot really does summon a thunderstorm.) When considered as applications, an IF game is small, monolithic, and extremely self-entangled. That’s just the nature of the field.

You still want to group together related concepts; that’s important even in a medium-sized game. If you want to do that by making a bunch of properties on a special out-of-world object, great! I7 also lets you group things with section headers. Or you can go back to old-fashioned fancy naming: “sponge-moisture”, “sponge-color”, “sponge-dirtiness” – grouped by a common prefix. Honestly, when I’m writing I7 code, I use all three strategies.

Most IF games are written by one person, so accidental name collisions are not much of an issue. On the other hand most IF games use extensions. Extensions have to be extra careful about namespacing, because I7 doesn’t have a way to have truly private declarations. If you’re writing an extension, you really have to choose names which will not accidentally collide with any other extension or any plausible bit of game code.

(But this is not a global-variable issue. As I said, everything is global, so the extension author has to take the same care with table names, phrase names, kind names, and so on.)

So, to sum up, pick a style that works for you.

1 Like

We have to separate the issue of good practice (ie, doing things to prevent bugs) from good style (ie, writing code that is idiomatic, understandable, and lessens cognitive load). Style is, largely, about aesthetic and communication, rather than about the technical properties of the code. This is important mostly if you intend to share your code (it’s an extension or you’re going to release your game’s source).

So the issue with “the sponge can be dry or moist” being better than “sponge-moistness is a truth state that varies” isn’t because the latter is unsafe, but because it’s less idiomatic and stylistically worse. I7 is designed so statements about the interior state can be phrased in the same way as statements about the game world:

if the sponge is moist: [...]

Using global variables rather than object properties gets away from that:

if sponge-moistness is true: [...]

There’s a related issue that named values are easier to modify later; if we take the former route, we can change it later:

The sponge can be dry, moist, or soaked.

Whereas, with the other approach:

The sponge-moistness is a number that varies.

[...]

If the sponge-moistness is 1: [Do this for every instance of this check.]

With regards to making configurable extensions, that’s one case where using global variables is sensical (cf I7’s own usage of them to set various global options). If a lot of user configuration is required, using a table might be better.

I think you’re overstating the differences. You can use a dry/moist/soaked kind-of-value (enum) for a global, although it takes extra verbiage to set up.

Also: the fact that “verbiage about the game world” works best for objects is a limitation of Inform, really. Inform is built around predicates (“X is Y, if X is Y, now X is Y”), but zero-object predicates are a gap. “It is raining” (“if it is raining”, “now it is raining”) is perfectly good idiomatic English which has no object. It’s a statement about the world in general, or at least about the part the speaker cares about. (The “it” is a placeholder, not a pronoun.) I wish Inform allowed that sort of thing; I’d use it plenty.

(There are practical issues with that particular phrasing, obviously – Inform always tries to treat “it” as a pronoun. But that isn’t my point here.)

1 Like

Okay. Jeez. I’ll turn off auto section numbering just cause you told me. I thought it was a feature. I didn’t realize it was speeding global warming.

So what general principles do people use to organize their stories? Perhaps story metadata at the top, includes, … then what? I personally try to put generally applicable rules at the end of my story. For instance, the rule for cutting a piece of paper would go in the middle, after the paper is defined, but the rule for cutting in general would go at the very end. Though I’m forced to define kinds of things and such at the beginning of the story due to syntactic constraints.

You can, but “if the sponge-moistness is moist” is still worse than “if the sponge is moist”, I think. I do think that you should use enumerated values whenever possible even for globals; eg, “if the current weather is rain” is better than “if the weather-state is 2”.

Zarf - thank you for that explanation about global variables, I found it most interesting.

And you, sir, thank you for making me laugh.

1 Like

Yeah, the explanations are super helpful. Thanks!

You can think of global variables vs object variables a little bit like the choice of instead or check and carry out rules: is there even the slightest chance what I’m working on will apply to more than one object? If so then see if I can generalise it for a kind.

Hm. So how would you feel about ‘if the sponge-moistness of the sponge is as-moist-as-a-slightly-moist-sponge’?

@Hanon, global warmer - Yeah, take that Hanon!

Re: Global variables - Yeah, I got annoyed that when I started Inform, someone said ‘DON’T USE GLOBALS!’. And I slavishly took that to heart and used to go around shamefully labelling my globals [GLOBAL] in the source, as if they were lepers. Turns out there was never anything wrong with them.

It’s true that occasionally I was stamping on my own foot by not attaching a variable to the relevant entity, but for me I was coming from BASIC and 8-bit Applesoft. It took me awhile to not just make all variables numbers, like ‘now the weather is 2’.

-Wade

I have metadata and inclusions at the top, things that I least want to repeatedly scroll through at the very bottom (EG weird baked-in extensions and hacks) so that I don’t have to repeatedly scroll through them, and the rest in the middle.

I’ve said it before, but I think it’s hard to start organisation in Inform because you can organise anyway you like, which can paralyse you with choice. Once you have started to decide how you like to organise things, it’s good for you personally because you can keep on doing it that way, but in terms of others’ ability to read it - when and if that’s relevant - it’s always difficult to make that first entry into someone else’s organisational scheme.

In terms of my own ‘the rest in the middle’, you can find the organised source for a whole game of mine here:

ifdb.tads.org/viewgame?id=6kko9va64c4o5jan

The advantage of this particular game is that’s both compact and complete, and the source is from Inform 6L38.

You can also visit the following search on IFDB to see games which have I7 source available for more ideas:

ifdb.tads.org/search?searchfor=t … 0available

  • Wade

As a former programmer, I like this list. New INFORM 7 authors take note.

1 Like