PunyInform vs Inform 6: A Comparison

Thought I’d do a short comparison between PunyInform and the Inform 6 standard library, for anyone wondering if Puny is for them.

What is this PunyInform thing?

It’s a library for the Inform 6 programming language, optimized for producing Z-code games playable on 8-bit platforms. It’s very similar to the Inform 6 standard library.

Oh, so it’s the same library, only smaller and faster?

No.

As we’re trying to make people aware of PunyInform’s existence, and new people try it out, we keep getting back to one big snag: “But my existing Inform 6 project doesn’t compile with PunyInform.” Well, that’s true. These libraries are not the same. We actually started writing our own library from scratch, but as we progressed, we saw that we needed more and more of the same features that Inform 6 already provided and, not surprisingly, that pretty much all of Graham’s design choices for Inform 6 came naturally or were very well thought-through and we just got in trouble if we tried to do it differently. Also, we thought it would be beneficial if authors could adopt their existing Inform 6 projects with no more fuss than necessary. So, we adopted the strategy that we copy the Inform 6 library’s way of doing things unless we think there’s a clear advantage in doing it another way, and we keep looking for ways to make the code smaller and faster. Also, we cut out features which are less than necessary and/or require a lot of code and/or are impossible to do in z3 games, since we wanted PunyInform to be 100% functional for z3 games too and as compact as possible. Additionally, some features which we thought would be really nice to have but all game projects may not require them were made optional.

Advantages of PunyInform

  • The library produces smaller and faster code.
  • Several parts of the library are disabled by default, making the code smaller unless you decide to use them.
  • Games can be compiled to z3 format.
  • The library creates fewer objects, which matters for z3 games, where the maximum # of objects is 255. With PunyInform, the game author can create 248 objects, vs 230 with the standard library.

Advantages of the Inform 6 standard library

  • Very well tested.
  • The parser has less rough edges and allows the game author to meddle with the parsing process a bit more.
  • Better debugging capabilitites.
  • Games can be compiled to Glulx format.
  • Handles identical objects, like a set of gold coins where you can pick one up and leave the rest.
  • The entire library has been carefully adapted to be easy to translate to other languages.
  • Apart from the default 2nd person perspective and present tense, the library also handles 1st person and 3rd person perspective and past tense.

What code has to change when porting a game from Inform 6 to PunyInform?

  • The basic code structure of a game is slightly different. You include the files “globals.h” and “puny.h” instead of “parser”, “verblib” and “grammar”. Some routines etc may need to be moved around in the code for everything to work.
  • If you use identical objects, change your design.
  • The process of replacing library messages is different.
  • The Compass object is gone, and all the direction objects have been merged into a single object. For this reason you typically need to change code which handles directions.
  • PunyInform doesn’t have the extremely versatile routine WriteListFrom to print what’s in/on an object, but a simpler replacement routine called PrintContents.
  • Some library entry point routines are not supported. If you have used such routines, you need to find other ways of getting the effect you want.
  • The set of verbs and the grammar tables are not the same. You may encounter actions which are not supported, in which case you need to implement them yourself, or the exact wording the player can use in the standard library doesn’t work in PunyInform.
  • TEST, TEST and TEST the game to see what isn’t working the way you want it to work. Remember, you are moving from one library to another, they just happen to be quite similar.

Why would you choose to use PunyInform over the standard library

We can really only see two reasons: You want your game to run on small and slow computers OR you want to compile your game to z8 format and you want a bit more room for game data.

So, this size difference, how big is it?

I have worked with Dave Footitt to adopt his Inform 6 game Calypso to PunyInform. His source code can now be compiled using either library - you just define the constant USE_PUNY at the beginning to compile with PunyInform or leave it out to compile with the standard library.

Using PunyInform v1.5 and Inform 6.12.2 (which is what I had at hand), I compiled the game to z5 format. Using abbreviations, with strict error checking disabled, and unused routines being left out, the standard library version is 80172 bytes (plus padding), while the PunyInform version is 48040 bytes. Thus, the PunyInform version is 32132 bytes smaller. In this case, that means the game is 40% smaller. This, of course, makes a huge difference when playing on computers with 32-64 KB of RAM, like the 8-bit computers typically have. For larger games, you can expect the difference in bytes to be about the same, while the difference in % will of course be smaller.

You can look at the source code at https://github.com/dave-f/calypso and you can download and try the two different z5 files at https://drive.google.com/drive/folders/1aMzMS7Yp37HDHc9n9IQB8rbd4C-3xAhM?usp=sharing

12 Likes

Some verbs have a totally incompatible grammar depending on the version of the libraries; this is the case of the verb Climb (no preposition is similar).
PunyInform:

Verb 'climb' 'scale'
	* 'into'/'onto' noun                        -> Enter
	* 'out' 'of'/'from' noun                    -> Exit;

Inform Library 6.12.3:

Verb 'climb' 'scale'
    * noun                                      -> Climb
    * 'up'/'over' noun                          -> Climb;

Isn’t that a problem?

They are indeed different.

Some of the actions supported by the standard library are not supported by PunyInform, and in some cases the grammar is different.

If you need a certain action to work in your game and it doesn’t, extend and replace grammar tables to get the result you want. You can also suggest a change in PunyInform, either by filing an issue at https://github.com/johanberntsson/PunyInform/issues or by contacting me directly.

1 Like

I have updated the section on what you need to change when converting source code from Inform 6 to PunyInform.

However, keep in mind that the main purpose of PunyInform is not to be a library you convert all your old Inform 6 games to. We made it similar to Inform 6 mainly so that people who are used to coding in Inform 6 can easily get into using PunyInform. It is often pretty easy to convert an existing project, but at the very least, expect to do a lot of testing and find out what doesn’t work the way you want it to.

3 Likes

As I wrote elsewhere, I noted that Metro84 is more indicated when porting old inform 5/6 games (yes, I tested with a pair of lingering I5.x WIP, chosen because they don’t use the deprecated Nearby), and puny is more indicated for new works.

Best regards from Italy,
dott. Piergiorgio.

2 Likes

I notice there is no ChangePlayer() function in PunyInform. Is this because the leaner system lacks the features that required extra bookkeeping in the Inform library? I notice that most of the code in the Inform 6 library’s ChangePlayer() is about managing the narrative_voice feature.

Is it as simple as just setting player = new_player_obj and calling it a day, or would there be a common short pattern that users would want to write in their own functions?

1 Like

I’d say the reason ChangePlayer() is not included is that we haven’t looked at including it yet, and the reason for this is that it’s not a very important feature. I would say only a small number of Inform 6 games make use of the feature.

Still, we may yet include it, either in the core library, as an optional addition, as an extension, or we may give an example of how to implement it yourself.

1 Like

with earlier (1980s vintage) IF language, I handle player “changing” Fregoli-style, that is, same actor, different costume, props &c. (taking the idea from the ancient stage art of quick-change)

Even the crudest 1980s IF language/creator (for “creator” I mean table-driven IF system, the best known being The Quill) allows PC teleport, moving in/out objects between inventory and not-in-game status (often called “limbo” in 1980s languages/creators) and variable/flag settings, and these are the basic ingredients for a quick-change of the PC object into different PC character.

So, I guess that one can have multiple character with only one PC object with punyInform, with an appropriate “Fregoli” system.

Best regards from Italy,
dott. Piergiorgio.

1 Like

As far as I can tell, PunyInform can even do one better than this, since it still lets you reassign the player variable.

I6lib’s ChangePlayer routine does exactly that, and also some miscellaneous manipulations to make sure that the previous player object can be referred to as “my former self”, that the new player object becomes transparent (so that you can see your own inventory), that you didn’t try to change the player to nothing, and so on.

Which is nice, but this sort of convenience is also the first thing to strip out for efficiency on retro machines. (I figure authors using PunyInform are instead expected to declare all potential player-objects transparent, to not set the player variable to null, and so on, all on their own. Such is the price of efficiency.)

3 Likes

Yes, I was looking at the function and the most useful code seems to be the way it handles the location/real_location dance correctly if you ChangePlayer() while in a dark room. That’s handy, but as @Draconis said it’s the kind of thing someone using a constrained library would just leave until it actually became a problem in a real story situation.

The transparent handling is not just about declaration, as ChangePlayer() is designed for a perspective shift within a single room. So an NPC would be ~transparent during interactions until the player “became” that character, at which point they’d suddenly be able to run inventory and see what the formerly-NPC object held.

The only other thing that seems useful is the passing on of the flag to print “(as formerly-NPC)” in the status bar, which may be too far out of scope for PunyInform as so many of its target platforms are 40 columns wide.

Indeed I’m not sure if I will need the use ChangePlayer: my penchant in multi-PC games are either “different perspectives on things” (like, how a passenger and a sailor see a ship) or “generational” (think first things first without time travel, e.g. grandpa put the safe’s key inside the, well, grandfather’s clock, then grandson recover it decades later…)

so, the point is what place the PC swithing has in the plot, story and narration…

Best regards from Italy,
dott. Piergiorgio.

I have added an example game where you can switch the PC: https://github.com/johanberntsson/PunyInform/blob/master/howto/change_player.inf

4 Likes

As PunyInform 2.0 has recently been released, I eventually decided to bite the bullet and give it a go. I took a copy of an (almost finished) game that was written using the standard library and made a few changes as per the advice in this thread and the manuals. There were a few unexpected surprises, but the process was fairly quick and painless. Basically, by a process of trial and error, I found out which of the optional things needed to be included (e.g. OPTIONAL_FULL_SCORE), which of the unsupported things needed to be deleted (e.g. ChooseObjects) and what needed to be added (e.g. LookUnder).

The compiled game was 65 KB compared to the original’s 111 KB, both z5 files. That’s quite a significant saving.

I am now wondering “what’s the point?” Should I start using PunyInform and convert all my games or should I just stick to what I know?

The thing that worries me a bit is that I can’t compile to Glulx, so if I decide to add graphics to a game, I have to revert to the standard library.

Anyway, the reason for this post is to ask if there is a quick, systematic guide to what needs to be done to convert an existing Inform 6 game to PunyInform? I know that some of the info is in the doco, but there’s also quite a bit that isn’t.

Interesting to hear about your experience in trying this!

I’m afraid the closest thing is what’s under the headline “What code has to change when porting a game from Inform 6 to PunyInform?” in the first post in this thread.

It’s quite possible to write your game source in a way that lets you compile it using either the standard library or PunyInform. Testbench, included in the PunyInform distribution, does this - if you compile it to z8 it uses the standard library, otherwise it uses PunyInform. Calypso can also be compiled with both (there’s a constnant at the beginning of the source). It does mean some optionals in PunyInform can’t be used, like Simple Doors or Ordered Timers, and you sometimes have to provide two alternative pieces of code to do the same thing.

PunyInform was never meant to be a drop-in replacement for the standard library. We just wanted it to be as easy as possible for people used to Inform 6 to get started with PunyInform. As it turned out, we ended up copying a lot of code and even more of the concepts from the standard library. We’re not hesitant to add stuff that makes them diverge though, if it makes PunyInform better. And we make sure to document everything that’s different. If you encounter something which is different and it’s not covered in the manual, please let us know. You can file changes to the documentation as issues on Github.

3 Likes

No problem. I can write my own notes, but I thought it was worthwhile asking.

One thing I noticed in the manual (manual_v2_0.pdf) was that on page 14 under Look, it said that the describe property wasn’t supported, then a couple of sentences later, it said “If the object provides describe…” I think the second reference should be description.

One irritating thing I noticed was that the prologue text in Initialise doesn’t throw a new line before the banner.

Some grammatical incompatibilities can create problems that are difficult to detect (e.g. throw), but the most delicate part is the grammar related to movement.

Yes, I noticed that. I quite often use verbs like CLIMB for movement, so I’ll have to change them. I think I’ll need to draw up a table with the differences between Inform 6 and PunyInform grammar. Inform 6 has a lot of really crappy grammar. If PunyInform fixes that, then that’s a bonus. I know there are verbs like READ where I always do my own thing, so I’ll have to see how PunyInform treats it.

Question for @fredrik: The manuals say that your entry point routines have to be defined between including globals and puny. Is that really necessary, or just a recommendation? I’m only asking because I normally define them towards the end of my code, after all the object definitions and before the grammar.

Ah, that needs to be clarified. What the text aims to say is that the room object can’t use describe (which it can with the standard library), but objects in the room can.

Ah. Thanks. Of course it should.

In theory they can be defined before including globals.h, but if they use any global variables that will fail.

You may be able to put some of them after including puny.h as well, but it’s likely hit and miss.

1 Like

Another thing I noticed was that there is no male attribute. The doco makes the presumption that if an object is animate, then it is male by default. But there are situations where the object is not animate, but you still want it to be male. For example, imagine my game has a male dog. I can’t make him animate, because I need to pick him up, but I still want him to be referred to as ‘he’ or ‘him’ in responses, not ‘it’. Is that possible?

1 Like

It’s not currently supported by the library no. Personally, even with the standard library, I’d make it animate and handle Take and possibly Remove in the dog’s before routine, since making it animate also gives me the ability to use life and orders, and I’ll get sensible responses for most actions.

2 Likes