I got into the weeds a bit with some brief coding I did. I started with this:
to open-passage (rm - a room) and (di - a direction):
now rm is mapped di of location of player;
now location of player is mapped (opposite of di) of rm;
While we could of course define
rm2 is northeast of rm1.
check going northeast in rm1 when rm2-available-flag is false: say "Not yet you don't." instead;
and that’d work well in general, that would give us an idea that rm2 was there, and I don’t want that yet. (Perhaps we hook around to Rm2 and find a secret passage back to rm1 for later, for the player’s convenience.)
So I wrote this stub, then a week later typed open-psg northeast and rm1 which threw an error because I swapped the variables. Simple enough to fix. But I didn’t want to run into it again. So I tried to add …
to open-psg (di - a direction) and (rm - a room):
open-psg rm and di;
This overloads “open-psg” as a function. But it feels intuitive and lowers my blood pressure a bit for the next time I switch the direction and the room.
Now, I have three questions.
is there something under the hood that may cause things to blow up?
if no to 1, have I violated some tenet of good I7 programming, or good programming in general, that I don’t know about?
how does inform react to this sort of overloading in general? Does it even care, as long as the parameters (or their order) is different?
I notice if I try
to say x: “1.”
to say x: “2.”
This compiles without warning. I forget which trumps which. But it makes me worry I’m stepping on something else I don’t know about.
Sorry that I’m not answering any of your three questions, but I’m just trying to understand the original goal.
You don’t like the check rule because the text implies rm2 is there. So that’s an unsatisfactory way of blocking the move.
(EDITED below - fixed directions)
There are lots of way of connecting things on the fly. I suppose my favourite is simply to map the rooms where they’ll ultimately be in the beginning (e.g. rm1 is a room. rm2 is northeast of rm1.) Then add a:
When play begins: change the southwest exit of rm2 to nothing.
Now the return journey from rm2 is already set up. In rm1, there’s no connection to rm2, so you don’t have to police that. Later, when you’re ready to open the way, you just say ‘change the northeast exit of rm1 to rm2’ and they fit back together. This avoids you having to actually remap anything.
Hmm … that does work, and it works well. (change the exit vs now r1 is mapped seem to be the same thing. I’m not sure how I7 translates to I6. Maybe I should look into that.)
An additional use case here is that I often may shuffle rooms during development. So if I want to, say, change something from a north/south passage to an east/west passage, I can just change “north” to “east” with one word. Or up or inside. So that flexibility means I don’t have to change several things in the code.
I’m making a few assumptions here–that the map opens up with no bendy directions (e.g. room X is north of Y, Y is easy of X)–but one of the big reasons I wanted to do this is, if I have 5 or so such room pairs with secret locations, it means fewer lines of code. It’s something I’ve reused for developing a few projects.
The code is slightly more flexible and concise, but the disadvantage is that it’s not immediately apparent where the exits will be, if someone wants to debug it. (For that I just make a trizbort map.)
So it’s a small stub, nothing earth shaking … the Inform 7 code works nicely, but I was curious about overloading a function as well.
I’m curious about your example code. I can’t get it to compile in either 6M62 or 10.1. Are you using a different version? Do you have any other specially-defined code that matters for these phrases?
Specifically, the compiler seems to balk at using a direction variable (in this case di) in the now ... is mapped .. of... statement.
As I understand it, the way the compiler sees these things is in terms of:
the kinds of the variable parts, and the order of those kinds
the exact words before/between/after the variable parts
In order to look “the same”, the declaration has to have the same kinds for its variable parts, in the same order, and in addition all words before/between/after them have to be 100% identical. Unless those conditions apply, the compiler will see them as applying to different situations.
In your case, you are varying the first word (open-passage vs. open-psg), so these phrases would be classed as different no matter what. Even if you used the same before/between/after words, the compiler would see them as different because one version has a room followed by direction, while the other has a direction followed by room. It should be perfectly legal to declare
To open-passage (rm - a room) and (di - a direction):
now rm is mapped di of location of player;
now location of player is mapped (opposite of di) of rm;
To open-passage (di - a direction) and (rm - a room):
now rm is mapped di of location of player;
now location of player is mapped (opposite of di) of rm;
and then forget about the order of the two arguments. (Note, however, that the compiler does not seem to like these in practice… but only because of the statements inside the phrases. Having two versions of a phrase with inverse argument order seems to work fine in other cases – even this case if the phrases are defined at the I6 level.)
I think the intent of the system is to allow more natural expression, though, in this case via adding prepositions or other context words to the phrase. You might go with
To open up a passage leading (di - a direction) to (rm - a room):
now rm is mapped di of location of player;
now location of player is mapped (opposite of di) of rm;
which makes it harder to forget which argument goes where when using the phrase.
Oh, this is kind of embarrassing … using 6G60, I had originally used “Now X is mapped north of Y” before creating the function, where I changed it to this. Which Wade noted he used, and I believe he’s using the latest version.
to open-psg (di - a direction) and (rm - a room):
let lp be location of player;
change di exit of lp to rm;
change (opposite of di) exit of rm to lp;
Thanks for following up … yes, I think there should be a way to allow more natural expression. For whatever reason, I kind of balk at using
to (verb) (variable 1) (preposition) (variable 2):
As I forget Inform can handle that! (Maybe I have gotten my own frustration with occasionally forgetting prepositions in standard Inform programming.) I still treat it like a standard function you’d see in a non-natural-language programming language. So that’s a mental block.
Nah. This is one of the benefits of Inform’s strong typing system: it always knows the types of the things you’re passing around, and can choose the right one at compile-time. The mad scientists spend enough time hacking around the type system when it gets in our way; you might as well reap some benefits from it in return!
That’s subjective, really, but in my opinion the most important factor of good I7 style is that it’s easy to read, and you’re not making that any harder.
As usual in Inform, specific beats general. In this case, the two definitions can never conflict, but you can also have e.g. a definition for “to foo (O - a thing)” and “to foo (O - a person)” and “to foo (O - an animal)” and “to foo (O - Rover)” and it’ll pick the most specific one.
Do you mean in #3, the most specific type that can be inferred at compile time? Can to foo (O - Rover) be executed if the argument is a variable; I.e., can I7 have infer that a variable refers to a specific instance (Rover) instead of a kind (animal)?
Or rather—the ordering by specificity happens at compile-time, but deciding which of those to use happens at runtime. So if you have separate rules for “thing”, “person”, “animal”, and “Rover”, then call “foo the noun”, it’ll function the way you expect.
Thanks all … this question was sort of a couple questions in one. But it’s great to be able to understand things.
I’ve mentioned it before but starting with Inform I remember how I didn’t ask questions because I wouldn’t really use or understand the answers. Now sometimes I don’t because, well, I have programmed a while, I should know it, right?
For the actual function, I had a think about proper English for defining a function of one or two words (I liked @otistdog’s suggestion of using to instead of and, but I needed to keep the function name simple-stupid for myself)
to reveal (rm - a room) to (di - a direction):
let lp be location of player;
change di exit of lp to rm;
change (opposite of di) exit of rm to lp;
This will wipe out the ambiguity of if I should put the room or direction first.
And it’s cool to know that I can fiddle with parameter order with no problem.