Showing posts with label Coding. Show all posts
Showing posts with label Coding. Show all posts

07/08/2023

QM: Why don't I have the patience to learn programming?

Why don't I have the patience to learn programming?

This question is part of the reason.

I’m not suggesting it is your fault. I’m saying that prospective programmers are taught to sabotage themselves, and many quite reasonably decide to give up.

The darker path

No, it's the question itself that's at fault. “Why don't I have the patience [required] to learn programming?”

That question is a trap.

It assumes impatience is the reason we fail. It blames an intrinsic, undefined trait. It comes with its own conclusion (“I don’t have [the innate ability x], therefore I can’t ever learn [the skill y]”). It suggests the issue stems from an intellectual or moral failing.

In short, it’s just not a helpful approach to learning something new. Every time you ask yourself that question, you reinforce the same ideas:

  1. “I should learn ‘programming’.”
  2. “I don’t have what it takes.”
  3. “Learning to program is hard and demanding.”

None of them help. All they do is hold you back.

I know it doesn’t feel that way. Trust me, I know. I’m a C++ programmer with ADHD and apathetic tendencies. I can’t say for sure how you work, I can only infer it from the question itself, but I think I can help.

And I think the best way to help you is by shifting the way you look at programming and learning.

Reframing

Yes, patience helps when you code, coding can be hard, and not everyone is equally gifted at it. None of that stopped me. In the end, none of it will stop you.

“Learning programming,” too, is a passive, empty concept. Make it active and meaningful. You want to read cool books about exciting stuff — you do not want to “learn reading.”

One more thing (and this is important): I’m not saying your attitude is what makes a coder. “Positive thinking,” the idea that imagining it hard enough will make it happen, is harmful bullshit peddled by charlatans. The idea that “if you struggle at it, you’re a failure” is toxic nonsense. Saying you just need the “passion” to “realize your dreams” is crap, too.

The right question

So don’t bother with the question: it has no useful answer. You already have the question you need, which is far simpler: “do I want to make something fun on my computer?”

If the answer is “yes,” then do it.

Have someone install Python on your machine, and teach you how to print something to the screen. Now have the program ask for a name, and print it to the screen. Your name. Run it. See it. You built this.

That’s fun, right? Make the text repeat itself. See if you can get a graphical figure (maybe made from letters) on the screen. Make it move. Play with it.

Build a maze. See what happens. Save all the time. If the program crashes, that’s alright. If something doesn’t work, great! We’re playing. We’re experimenting. We’re discovering new things and making pleasing shapes on the machine.

We hit walls. We trip over details we never noticed. As we do, we learn new patterns and nuances, and deepen our understanding. We’re stretching our ability, getting frustrated, then beating the obstacle, and that feels good.

And then we do it again.

The end note

What you just read is programming. Can you learn that? I think you can. As long as you’re playing around, relaxed, without judgment, programming doesn’t have to be harder than that.

Play. Laugh. Learn. Share it with friends.

Above all, fail and fail often: that’s how you improve.

You’ll get there, and if you don’t, or if it doesn’t happen quickly, or if you feel embarrassed, then remember: it’s not a big deal. It says nothing about your value as a person.

It’s just coding. That’s all it needs to be.

10/09/2021

QM: Do you think C++ is beautiful?

Do you think C++ is beautiful?

God no. It works. It’s powerful. But beautiful? No.

C++ is all power and sharp edges. It’s pretty much a Brutalist fortress composed from wildly disparate architectural viewpoints. Syntactically, it’s rather cluttered, with no real unifying principle. It’s a bric-à-brac if you’re generous, and a crash site if you’re not.

However, C++ is much better than it used to be. Original C++ was very messy. Expressing yourself succinctly in it was a difficult task. C++17, by contrast, is straightforward, and allows you much terser and more orthogonal constructions, safer memory management, less clutter, etc. Consider iterating over a vector in C++98:

for(std::vector::const_iterator p= pairs.begin() ; p!=pairs.end() ; ++p) { 
	std::cout<< p->name<< ": " << p->val<< '\n'; 
} 

Now the same thing in C++11:

for (const auto& p : pairs) { 
	std::cout << p->name << ": " << p->val << '\n'; 
}

And in C++20:

ranges::for_each (pairs, [this] (auto& p) 
   { std::cout << std::format("{}: {}\n", p->name, p->val); });

Now adding some usings and new capabilities, we get this:

for_each (pairs, [&] (auto& p) { 
   print("{name}: {val}\n",
      "name"_a=p->name, "val"_a=p->value);
});

Dismissing that as mere syntactic sugar misses the point, which compared to older C++ versions and C is this:

  • Modern C++ lets you express yourself with less noise.
  • Modern C++ lets you write code that is more generic.
  • Modern C++ avoids entire classes of error, particularly when following common patterns and conventions.

C++ is heading somewhere. It’s converging on a leaner, tighter subset. Despite the requirement to be mostly backward compatible with C++, we’ve already seen careful excision of things like diacritics and the virtual deprecation of #define, bitwise arithmetic, spurious operator overloading et cetera.

But C++ wasn’t written to be beautiful, and it shows. Even the idealized C++ that Stroustrup is clearly striving toward is an unlovely, brutish thing. But sometimes, for some jobs, you need a combine harvester rather than a Camaro.

Lisp, Smalltalk, Prolog, Haskell, Python — these could be said to be beautiful. In my opinion, beauty follows criteria that neither C nor C++ satisfies:

  • Conceptual elegance. In Lisp, everything is a list. In Prolog, everything is either a world fact, an implication, or a query. In Smalltalk, everything is objects and messages. Haskell wants everything to be a mathematical, stateless function chain, where Python just wants everything to be as simple as it possibly could. C++ does have a philosophy, but it’s murky and syntactically impenetrable; C has “I’m portable machine code!” which really is more of a mission statement than a coherent concept.
  • Terse, expressive syntax. Smalltalk can famously be described on the back of a postcard. Lisp and Forth can be derived from almost nothing. C is pretty good here in the terseness metric, although I think its legibility is overstated. Prolog, similarly, does much with very little. By contrast, while it’s possible, you have to really know your C++ to consistently produce terse and idiomatic code.
  • High level of abstraction. A beautiful language is one in which you merely have to model the problem in the domain of the language to have the solution suggest itself. Again, not a C++ hallmark unless you’ve learned how to do this as an orthogonal discipline, and C provides virtually no abstraction other than that of memory and flow constructs.
  • Legibility. If not for this metric, Forth (and possibly Perl) would probably make the list. A truly elegant language is not cryptic but can be read and understood in a straightforward way. Code written in C and C++, by contrast, can be famously illegible.

There are other metrics, but these are the ones I value. In closing, however, I have to say that while elegance is always a desideratum, it is not a requirement. Sometimes, tackling a big, sprawling language can be a fun challenge, while a more streamlined version of the same thing would just feel empty and impersonal.


Notes on the Quora Migration: this piece originally appeared on Quora. Since Quora is no longer what it was, I'm migrating my content here.

QM: The bare minimum

I have an old computer having having intel pentium processor with 2.00 GHZ speed, 1GB RAM and only 150 GB hard drive. I have a passion to learn programming. Can I learn with this device?

This, my friend, is the Commodore 64.

It was launched in the year 1982 at a price point of $595 ($1,500 in today's money). Its 6510 processor ran at roughly 1 MHz, it had 64 kB of RAM, could be fitted with a casette tape player or (if you had the cash) a floppy disk-drive. It had no true operating system, but booted you directly into a BASIC interpreter. As for hard drives, Internet, sample-quality sound or graphics with more than 16 colors, those were pure fantasies at the time, about as attainable and practical as ordering a unicorn by mail. And you know what?

It probably created more programmers than any other computer.

Yes, it was limited. That's actually a point in its favor, because we learn and grow as programmers by facing and overcoming limitations placed in our way. And to varying degrees, as many as ten million C-64 users did precisely that, because they had ideas, because they were challenged by the scarcity of resources, and because the barrier to entry was so low.

So. The computer you have is thousands of times faster, with over ten thousand times the memory, and nigh-infinite permanent storage that does in nanoseconds what would take minutes to load or save onto precious tape on the '64. Its Internet connection lets you download, for free, all the development tools and examples and tutorials you could ever need. With the proper OS, you can have it multitasking like a dream, and you'll never have to deal with not having memory protection, virtual memory, or any of the thousand things that didn't exist during the eighties.

Right, the conclusion. Well, the question was, "can I learn with this device?" And that is of course entirely up to you. But the idea that the computer itself would limit you is just... no. Compared to what most programmers throughout history used to learn their craft, the one you have is amazingly, mind-blowingly, ridiculously overpowered.


Notes on the Quora Migration: this piece originally appeared on Quora. Since Quora is no longer what it was, I'm migrating my content here.

QM: Do good programmers use Else?

Coming from a C/C++ legacy codebase written by self-taught engineers, I understand why someone would embrace this notion. You can only look at so many gigantic piles of nested if statements before you go "you know what? I'll just collapse the whole pile by exiting early using return statements." Before long, you'll clear away all these little methods that only branch when their various calls result in a null pointer, and you'll pat yourself on the back for having eliminated all the else statements. Tempting, then, to wonder when else is even necessary.

True, those else statements were redundant. That means very little. All it proves is that like any other tool, else can be misused. That doesn't make it a bad tool, it just means it was used in the wrong place. For short, well-considered routines, if-else is perfectly legitimate.


Notes on the Quora Migration: this piece originally appeared on Quora. Since Quora is no longer what it was, I'm migrating my content here.

18/09/2018

Setting the record straight on AMOS

I feel I have an apology to make.

One of my first posts, and the one people most seem to appreciate, is the one in which I absolutely slated AMOS for the Amiga as a programming language. I went to some lengths on the matter of how poorly I found AMOS to be constructed, how its organization was lackluster, and pointed to the inconsistency of its design and various choices made. Those were the things that frustrated me back when I was a weedy little sprog desperate to code games on the Amiga.

Which is all well and good, but that's not everything that is important about a language. A language isn't just its syntax or its implementation. The most important part of a language is the intangibles. The community. The accessibility. The culture.

AMOS had that. And what's more... it still does. In my post I made mention of François Lionet, the man who wrote AMOS. I paid him what was at best a backhanded compliment, in saying he was an able programmer. Not only did I undersell things (the man wrote a language that touched almost all of the Amiga's hardware, and in a fast but systems-friendly way), but I did the man himself a tremendous disservice.

AMOS had its share of flaws, yes. But if the alternative was not to push it out the door, aspiring Amiga coders would have had a much higher bar to clear.

And perhaps that was why my reaction to it was so negative. As the youngest boy in a well-to-do academic household, I grew up internalizing elitism and my supposedly fated intellectual superiority. AMOS was supposed to teach me how to attain full control over the machine, and yet learning its basics brought me no closer to understanding Assembler or C. I think my lingering resentment toward AMOS may be a reflection of my own reaction to a perceived failing, and the need to reframe AMOS as a condescending play-toy.

If that's true, I'd say it's high time I grew out of it. I now believe that François Lionet was entirely correct on several key points.

  • The Amiga community needed a REPL-capable language that was powerful, reasonably fast, and tailored to the machine. AMOS was that.
  • The playing field needed to be leveled. The Amiga base was largely split into gamers and power users, with few of the latter having the patience to educate the former. But coding should not just be the province of an enlightened priesthood. The Amiga, after all, always held the potential to be all things to all people. For all its flaws, AMOS democratized coding. That is a badge of honor.
  • AMOS is often good enough. It's not weak simply for not being Assembler, and you can pull off some pretty impressive things in AMOS if you know how. That fact is often overlooked, but no less true for all that, because the worth of a program isn't in its presentation. If you have a game that is shit in 16 colors and increase the colors to 256, then what you have now is slightly more colorful shit. What makes a good program? Solid concepts. Great art. Attention to detail. Clever use of algorithms. If your idea is good enough, it should be viable on the Amstrad.
  • Documentation is key. Most Amiga programmers wrote their own instructions, which tended to be confusing, omit key information, and generally required you to live inside the author's skull. Worse for me as a teen was that nobody seemed to acknowledge this, which left me with the impression of constantly missing something important. In AMOS, François Lionet produced a manual that actually made a degree of sense. While it still managed to confuse me in places (mainly in mixing AMOS-specific concepts with general Amiga ones), the manual was very readable, explained most concepts in a way that didn't confuse the reader, and was sensibly laid out.
  • It was inspiring. Where other communities were opaque and grudging, AMOS wanted to welcome you. Back then, I wanted coding to be a secret club, so I scoffed at the lack of gatekeeping. Even then, though, Lionet's honest celebration of aspiring coders shone through, and it was a great motivator. It's a pity I didn't fully appreciate that back then, but I treasure it all the more today. We need a more enthusiastic approach to computer programming and content creation, and AMOS had that in spades.

These factors are, I think, enough to excuse a litany of sins. It was enough to make me join the Amos group on Facebook, where François Lionet himself is a regular poster. AMOS may never be my holy grail, but I've taken to using it when I want to quickly slap some graphics on the screen or construct a table of precomputed values. Explorative development is quite quick, and less likely to crash the machine than Assembler or even C. I still would have preferred a system that didn't reinvent graphics handling or sandbox the system, but the existing AMOS is a flawed but solid product. François Lionet could have left it at that when he left Europress. He's working on Friend OS, and that could easily be his legacy. It would certainly be enough for most people.

Not for François Lionet, though.

François Lionet, it turns out, is more of a visionary than I gave him credit for. He's also a far greater person. Why? Well, aside from unfailing courtesy and unstinting helpfulness on his own Facebook group (which he does not, I must add, treat as his own private fiefdom even though he easily could), and disregarding his work and advocacy for the Amiga-like Friend OS, his sheer enthusiasm and investment in doing right by his fans should be an inspiration for all of us.

You know guys, what prevents me from coming back to AMOS source code and change it, is that I fear it will take me a long time to setup a proper dev environment with UAE, with disc and everything, editor, graphcx editor, assembler... all the necessary tools to work...

Once I have that, I am sure that I can find how to compile again very quickly...

But, if someone does that, that is, make me such machine, and provides me with a zip file with everything installed and ready to run in one click, I can try! It will be really fun to dive again into 68000 code, I will feel 30 years younger! And if in AGA you only allow one screen, full size, and only 16 colors rainbows (the first ones) or something like that, then it is not much to do! I think I can do that in a week-end...

What do you think?

The group erupted into standing ovation. A bit of faffing about ensued regarding just how this thing would be accomplished. But in the end, this was the conclusion, from the mouth of the Lionet himself:

OK guys. You have really cool ideas, and it would be so stupid to leave them get forgotten in the depths of FB.

I will act as an administrator now on this side, sorry, but if YOU want a better version of AMOS, there is no choice.

1. I create a post with bugs

2. You post bugs there, it will come back up if it is active. But I am not making it sticky, this would be really depressing for me to see it fill up every time I connect

3. I create a 'suggestion' post, and this one will be sticky :) (possible Michael Ness?)

4. I will delete each and everyone of the posts with suggestions and bugs after this one. But carry on with conversations please!

BTW: I will not read them after... let me look... Colin Vella (sorry, not read), ' if possible, .... :P

Good to be the king! :D (I'm not, or if I am, a Viking king, not a French one with white powder acting as a lady. Don't come too close to me, I will slash your throat so that you can have fun in paradise :) )

This is what being a true gentleman looks like. So that is why I owe François Lionet an apology: instead of the whining and picking out perceived flaws in his work, I should have celebrated the soul of a man who, 30 years after a computer's demise, still makes good on his promises to its community.

One poster on FB responded to François' offer by simply saying, "you legend!"

Simple, but beyond dispute.

So thank you, François Lionet. Appreciated or underrated, a legend you remain.

05/09/2018

Converting C into Assembler on the Amiga

Introduction

This article is basically a cheat-sheet for converting C code into Amiga Assembler. The basic method is not my own. I found a page on it a year or so back, but unfortunately, I forgot to save the link. This is my rendition of the method, and any errors in thought or application should be considered mine.

Most coders, whether on the Amiga or not, are familiar with the C language. Not everyone knows how to work with Assembler, though, and the bar for learning it can be daunting.

For people already conversant with C who want to learn Assembler, there's a solution: translating it yourself, by hand, at speed. That sounds like a tall order, and complex C is indeed hard to translate. But C doesn’t have to be complex in order to be powerful. If it turns out a reduced subset of C code can help to not only dip our toes into Assembler but to write it quickly and accurately (and I aim to demonstrate that it can), then it should be an avenue worth pursuing.

Our goal, then, is to write our program in C, and then render that code into legal 68k Assembler. At first glance that would be intimidating. However, by adding just a few self-imposed constraints, we can restructure the C code into a form less concise but much easier to translate.

This is a deceptively powerful technique. After all, compiled C is just the computer doing its uninspired best to write Assembler in the first place. It just does it much faster than a human, though sometimes less efficiently (particularly on older systems, where memory and CPU speeds impose constraints on the fancy optimizations the compiler can pull). Still, manual translation remains a proven method of producing a working Assembler program in short order. The added benefit is the greater insight into one's own code offered by manual translation.

From C to A in three steps

The procedure itself is unambiguous. It takes a C listing, and the end result is a rough sketch of the final yet-to-be-optimized Assembler code. We will most likely require a few Amiga-specific additions to get something up on the screen, but the resulting binary will otherwise be fully functional.

  1. Write the routine in C. Determine its correctness.
  2. Restructure the routine in accordance with the following constraints:
    1. Calculations must be on the form of [value] = [value] [sign] [number or variable] (ex: "x = x + 2"), nothing more complex.
    2. Comparisons must be on the form of [number or value] [comparator] [number or variable] (ex: "x != 2"), nothing more complex.
    3. Remove complex branching constructs. Replace with goto or function call.
    4. Remove loop constructs. Replace with goto.
    5. The only allowed conditional is a single-line if statement followed by a goto.
    6. Remove references to variable length strings, arrays or lists. Use statically sized arrays.
    7. Replace primitive functions with calls to OS functions on the target platform when convenient (ie. typedef).
    8. Rename variable names to resemble register names, where appropriate.
    9. Test that the code’s output is unchanged (i.e. is still correct).
  3. Translate this modified code into rough Assembler form, add Amiga-specific code (libraries, interrupts, hardware access) and, again, verify correctness.

How the method is used

To illustrate the method, we could try a simple example. Project Euler is a website that offers a series of problems in roughly ascending difficulty. Most of these problems are constructed in such a way as to make a brute-force solution computationally expensive.

I generally try to avoid spoilers. However, the very first Project Euler exercise should be considered reasonably easy for any CS student to solve in a handful of minutes. The Sieve of Eratosthenes provides a fairly good, conceptually simple solution. Better still, it yields a short enough listing to be manageable for us to translate. Note that will not translate the printout part of the routine, as it would just be a distraction.

Running this program yields a sum of 233168, which in hex is 0x38ed0. This is our expected result.

Next is to prepare the C listing for translation. Applying our list gives us the following modified C listing:

This is already pretty close to what we want, but we're still not there. We need to put registers in place of variables:

Except for the Printf() function, this is practically Assembler at this point. The instructions are now ready to be translated. The result:

Assembling the program results in a minor error, easily fixed by changing the addq instruction in the third loop to add.w.

As noted, the program should result in a value of 0x38ED0 in register d0. When we assemble the corrected listing and run it, it yields exactly that: ergo, the program works. The only bug we encountered stemmed from my attempt to optimize instruction size, which was not part of the method. Had I stuck to the script, the first attempt would have assembled and given the correct response.

Two things bear mention about our C implementation. When I wrote this, I declared three iterators (scoped to each for loop). Doing so is good high-level practice, but runs contrary to the Assembler ethos of porous scope. When preparing for translation, consider deliberately compromising scoped constructs or even declaring variables as global.

Regardless, the results speak for themselves. Judging by the above demonstration, the idea is sound.

14/06/2018

Incremental Tutorials #1: The Bootable Program

I grew up with my dad’s Amiga 2000. It was a brilliant machine that I desperately wanted to understand. The path was daunting, with countless steps and milestones along the way.

Although I did learn a lot, there were some I didn't manage. I kept circling back to one particular goal. The bootable disk. This was something the PC couldn't manage, and that for me somehow encapsulated what it meant to use the Amiga.

It's exactly what the name suggests. You place a floppy in the diskdrive, it loads, and then the game starts. I wanted to make such a disk. It was magic to me, the province of mighty game coders, and I was a kid dreaming the dreams of Icarus. I never did succeed, not back then. But as it turns out, it’s never too late to start.

Programs on the Amiga usually came in one of two categories. Either the program was meant to be used under Workbench (generally, that meant it was a utility), or it was designed to boot from floppy and would immediately kill the system in order to maximize those resources for running the program (this was usually the case for games). We will probably go into how to do that as a later refinement, but it all starts with this first lesson, which is booting from floppy.

Well, turns out it's not a difficult process. To that end, I’m making this our first incremental tutorial. It has but one, simple goal: to let you create a bootable disk containing a typical game or utility for the Amiga 2000.

This tutorial will be simple and rough. It will not be optimized in any significant way. The idea is to master the basic technique first, before we return and refine what we have into something smaller and punchier.

First iteration: the floppy that boots

Overview

This will be the first tutorial. The intended end result is a disk that will boot into an already existing program. This requires

  • adding a boot-block to the disk,
  • adding a program for us to boot, and
  • writing a suitable start-up sequence.

This is a reasonably straightforward task. I will stress that I'm assuming you use an emulated machine, as logistical issues of running on real hardware (like transferring ADFs to floppies, etc) won't be part of this tutorial.

Step One - adding a boot-block

All bootable disks start with a blank floppy. If you're using physical media, that's any old floppy disk you have lying around whose contents don't matter to you. If using an emulator, create a disk image such as an ADF file (UAE has a button for this).

Now, the next thing you do is boot your Workbench system disk (version doesn't matter). Once WB finishes loading, open a CLI window, and start typing.

format drive df0: name Lesson1_1

What follows is a prompt to format the disk, so pop out the Workbench disk. Insert the empty disk (making sure it's not write-protected), and hit return. Formatting will, unsurprisingly, wipe the disk, erasing all its data and leaving it blank. Next, we want to ensure the disk boots when you insert it into Df0: on startup. After the drive's settled, type:

install df0:

You'll be asked to swap the disks, but the program itself takes no appreciable time to run. That's basically it; you now have a disk that autoboots. Go ahead and try it by pressing CTRL+Amiga+Amiga. Once you're done, boot back into Workbench.

Step Two - adding a program

The idea here is to start a piece of code that doesn't need running under Workbench. My rationale for that is the fact that bootable disks often avoided using things they didn't need. In other words, we don't want to tie ourselves to having a running Workbench process. Following this stripped-down ethos, we want a dead simply program, one that doesn't use extra libs or indeed more than one executable. It seems pleasingly symmetric to use Pong for this, so we will: this PD version of Pong by Claudio Buraglio from 1991 satisfies all the conditions.

If you're running an emulated Amiga, transferring the binary is just a matter of loading the ADF like any disk. A real Amiga makes it a bit harder: I would recommend the PCMCIA to Compact Flash solution, a Gotek drive, or (if you're feeling old-school) a null-modem cable. Transferring it to a real machine can be nontrivial, but, again, beyond the scope of this tutorial.

Next, copy the Pong file to the disk.

Step Three - adding the startup-sequence

The final step is eminently simple. Create a folder named "s" on the Lesson1_1 disk. Whenever a disk boots, AmigaDOS checks the folder named "s" to see if it contains a file called "startup-sequence". As it's empty at present, we need to create that file.

Open a new CLI window. Type the following (assuming the disk is in df0:):

ed df0:s/startup-sequence

This should create a startup-sequence file. Type

Pong

, then an asterisk, then confirm by pressing Y. This will save the new startup-sequence.

Congratulations: you have an autobootable disk.

Conclusion

We now have a disk that will autoboot and run an existing program. It's still a systems-friendly program, and can be run under Workbench. The common OS startup routines are still in place. But we can boot.

If you're anything like me, you may be underwhelmed at this point. "What? It's that easy?"

On the one hand... yes, yes it is. On the other, though, 'easy' was really the point of this exercise. Every journey has to begin by one single step.

13/06/2018

Incremental Tutorials

This blog has lain silent for a while. I’ve been busy with real life, because real life must take precedence when you have work and children to consider. The main reason, though, was that I just couldn’t decide on how to finish the tutorial. The bar for learning graphics programming seemed just too high (because of course, I’d resolved not to resort to AMOS, which would have made it trivial). No book I read on the subject seemed to truly have what I needed, or to fit my setup, or be low-level enough for what I had in mind.

So there I sat, wondering why I couldn’t make headway. I felt stupid. I questioned if I was even smart enough to begin to understand the subject, let alone write about it authoritatively.

Eventually, I realized that the problem wasn’t intelligence or understanding, but that the underlying logic behind my tutorials was lacking. So I decided to change my approach. My original format was that of the typical tutorial: “this is what you want to do, here’s how you set things up, these are the steps you must take, and you’re done.” When written well, that gives you a good solution for achieving the goal at hand.

On reflection, I wanted something different. The standard tutorial is sequential. I don’t really want that: what I really want to do is to describe a creative process, and that process (at least for me) is not sequential but iterative.

Enter the incremental tutorial. Each tutorial consists of a number of self-contained posts. For each post, we add or modify one piece of functionality, while producing a valid product that does something. That means that each tutorial will have few steps, be of manageable simplicity, and that there will always be a checkpoint close at hand to retreat to, should anything go wrong.

I think this is a promising concept. It remains to be seen whether it's enough to take it all the way.

15/06/2017

Please stop referring to source code as "a code"

I follow programming-related topics on Quora. Lately, I've stumbled upon an odd turn of phrase. I'm speaking of the tendency to refer to code as "a code," as in "I wrote a code for a game."

I see these questions with increasing frequency:

How can I make a code harder to hack?

What does it mean to 'debug' a code?

What are the steps from writing a code to having a complete software?

What is the difference between a code and an algorithm?

How to reuse a code in Java? 

How do I write a code for login application in java?

How can I write a code for a rectangular box to write text in it?

How can I make a code that access a website and do things?

And so on. Unfortunately, this isn't a moment's lapse. I usually like it when people play with language, but this time, I balk. A typo is forgivable, but this isn't a typo. It's a hideous misapprehension inflicted on language itself. It's wrong.

Code is is never "a code." Code is code. I've been trying to discover why I am so repulsed by the addition of a simple pronoun. Why does it bother me so much?

It could just be snobbery on my part. I take pride in using language correctly. I'm frustrated when I feel other people aren't making the same effort.

It could be unfamiliarity with the vernacular. After all, I see a lot of Indian posters referring to it as "a code." The term alone shouldn't be offensive. If this is a mere colloquialism, it would be stupid and wrong of me quibble over minutia.

It could be gatekeeping: as a middling programmer, I could subconsciously be trying to exclude people based on arbitrary criteria and some notion of what a "pure" programmer should be, in order to keep the field more exclusive. (God, I hope that's not it.)


Regardless, I'm pretty sure it has to do with my perception of what programming should be. Because for me, as dirty a slog as coding ever gets in practice, the idea of programming is something beautiful. It's creation. It's building things out of things you've built, turtles all the way down.

"A code" can mean many things. It could be an opcode, or a secret message. But my most visceral association is that of cheat codes on 16-bit computers. You don't have to understand the game or the code: you enter it, you bypass the challenge, and are declared winner.

So when someone asks me, "could you give me a code for printing a file," what I actually hear is, "could you enter the cheat code for me?" A impression, I add, that isn't helped by so many of these questions being demands for a complete solution.

That, to me, feels like a mockery of what programming should be. Sadly, it seems there's a whole lot of CS students out there who subscribe to this idea of rote memorization, and a whole lot of faculties who encourage the practice.

Then again, should programming be hard? It used to be harder by far; the tools were worse, the information was unreliable and difficult to find, and you had to expend a lot more effort to reach the same result and reliability. Better tools, a democratization of techniques and information, and a more permissive approach to teaching meant anyone could become a programmer. The rise of open source and the quickened feedback loop of error reporting have made commercial programs more reliable than ever. So if programming is getting easier, is it really such a bad thing?

In short, do we as programmers prefer it to be an arcane domain, or do we embrace the paradigm shift?

I think the salient point is that no matter what happens, and no matter how the parameters of the profession change, a good programmer is one who resolves to remain a professional. If programming is made easier, why, then we use that freed-up headspace to learn more about the field.

A professional can't rely on cheats: they have to write programs that work. That program must be written judiciously, by a programmer who knows their domain and the language. And when such a program is done and compiled, it will do the job.

At that point, the misuse of a pronoun is a minor issue. Still heinous and disturbing, of course, but minor.

(Seriously though, please make them stop.)

14/06/2017

The worst language in the world

Preface

I wrote a popular answer on Quora. It involved an Amiga based language, and it occurred to me that it could be a good fit for the blog. And here we are.

Just remember though: while the post itself is jocular, the horror behind it is genuine. If you should decide to embark on this journey for yourself, gentle reader, be mindful of my warning. Heed the words of Signor Dante Alligheri.

Lasciate ogni speranza, voi che in Amos entrate

The Worst Language in the World

There are some really awful languages out there. I’m not counting the ones that are bad by design. Nobody’s seriously developing in Malbolge or INTERCAL or if they are, they’re presumably making some kind of masochistic point.

No, we’re talking real programming languages. Programming languages fit to purpose. Languages to make your life easier.

Programming semantics exist to shoulder cognitive burdens. They let us dispense with trivial code so that we don’t have to recreate old solutions. That way, we can focus on higher level code, the solutions and algorithms that really matter. Otherwise, we might as well all write in Assembler and be done with it.

In short, we leverage the power of programming languages to dispense with makework. When at their best, when coding a solution looks difficult and arduous, good programming languages are your best friend.

This is AMOS Professional, a BASIC variant for the Amiga personal computer.

It is not your friend.

Oh, it wants to be. It’ll always be there when you call. But somehow, that’s part of the problem.

This is your friend AMOS. Whenever it tells you about this great idea it just came up with? That’s how you know you should start running.

A brief history lesson

AMOS began on the Atari ST, in the form of the popular STOS BASIC. It was created by François Lionet and Constantin Sotiropoulos, then of Mandarin Software. Both were able programmers, with both vision and the ability to make that vision a reality: the noble goal of opening up the ST’s full multimedia capabilities to the user-base.

On release in 1988, STOS immediately grew popular, although not without earning its share of criticism. Two years later, the Amiga version (named AMOS) was released. You now no longer had to mind line numbers, and with the Amiga support you could now program the custom chips in various ways, with functions to manipulate the blitter, the copper, and various peripherals. It was more powerful, more polished, and more accessible than STOS. In fact, it was capable enough to allow you to write commercial grade software, or even games, for the Amiga.

In short, AMOS stands as a testament to the parable of the road to hell being paved with good intentions.

None of those things sound bad. What’s the problem?

The first issue is that of the runtime. AMOS is a black box. On paper, you need no knowledge of the innards of AMOS to produce a set number of impressive effects.

Notice I didn’t say “any number” effects? No, AMOS has a set bag of tricks which it thinks you should be allowed to employ. If what you want to do lies beyond that, tough luck. It enforces this limitation by encapsulating your code in the AMOS interpreter. This means the runtime will always stand between you and the actual machine, and even when it pretends it’s allowing direct access (such as with AREG and DREG), that’s actually not what’s happening under the hood. Even when you use the AMOS compiler so that the program is no longer interpreted, AMOS will still enforce this artificial separation.

If you want to do something under AMOS, that’s only easy as long as the programmers planned for it: if they didn’t, the runtime makes greater control all but impossible.

This, of course, also applies to access to AmigaOS.

AmigaOS was a fairly revolutionary operating system back in its day. It was lightweight and flexible and had nifty features like preemptive multitasking. It seems obvious that if you want to create a universal programming language for such a machine, it should produce applications for the OS. Europress disagreed, in effect creating an entirely separate and parallel graphical interface for AMOS programs. This was slow, bloated and unwieldy, even when compiled; compilation also made certain functions such as setting copper control to manual crash the computer. Above all else, it meant AMOS programs would always be visually recognizable, and so carry the distinct graphical signature of failure.

Second problem is the language itself. It’s shit.

Hey, aren’t you being a bit harsh?

You tell me. AMOS was written in the late eighties. It’s not as if we didn’t by then know perfectly well what sound language design principles looked like.

These are the hallmarks of a well designed language:

  • Elegance. A sparse design with a small set of highly useful keywords that behave more or less similarly. Function arguments always follow the same order, naming conventions are kept consistent, and the syntax encourages doing the right thing.
  • Expressiveness. An expressive language lets you describe problems in terms of the problem domain. This allows you to simplify the problem through abstraction. It also allows you to exclude categories of error, ideally at compile time, because of its semantics.
  • Consistency and simplicity. The language behaves in well-defined ways that let you reason about it. The simpler a language is, and the less unexpected its behavior, the easier it is to master.
  • Extensibility. A good language allows you to add new functionality to it. Ideally, such extensions should be functionally indistinguishable from core components of the language.
  • Power metrics. By which we’re talking execution speed, memory requirements, etc.

AMOS is the ugliest language I’ve ever used. Everything has keywords, and those keywords have names that frequently make no sense. There’s tons of them. With no consistent naming scheme or parameter succession, you’re forced to commit all these things to memory.

A sane language would structure this somehow using namespaces or packaging. In Java, hardly a paragon of elegance, an instruction might be invoked using

System.Security.Cryptography.AsymmetricAlgorithm

That’s a bit verbose, but the idea is clear: you go in the direction of organizing the language as specifically as possible, so that the keywords don’t conflict.

AMOS… chooses the opposite direction.

Wait… what does that even mean?

It means that other than inside comments and text strings, all the text in the editor (yes, that most certainly includes variables) is matched against existing keywords, of which there are hundreds. And if they match, case insensitively of course, the variable name is broken apart by the ever-helpful editor.

Look. Suppose you have this line of code:

Rain_Water_Level = 12
print "The water level is " + Rain_Water_Level + "!"

Looks like legal syntax, right? Unfortunately, turns out the word “Rain” is a keyword, so the variable name will be broken up. And since this occurs even case insensitively, good luck trying to write things like RAIN_water_level. That reduces the set of variables you can use to write descriptive code to an alarming degree, quickly making most code impenetrable. And yes, of course Cos, Sin and Tan are reserved keywords.

You may also notice that the language is not typed. Nor is it consistent: it will silently convert values for the print statement, in an effort to be helpful. Just like back in the day when Internet Explorer allowed incorrect code to still produce a usable webpage, this sort of help will sooner or later backfire as the errors overflow and you’re left with a turgid mess.

Under IE, of course, you could still enforce strict rendering. In AMOS, you cannot. It will cheerfully give you a coil of rope and then help you tie the knot just so.

This is horrible.

Oh, I’m just getting started. You see, there were some things AMOS was too slow to actually do. It’s an interpreted language after all, and what you needed for moving objects on the screen was speeds on the Assembly level. So what do you think they did?

…they let you use Assembly, to really leverage the processor?

Hahahahano. Not really. They created a whole new metalanguage called AMAL (AMOS Animation language) which you then have to write within AMOS. AMAL code is fed into AMOS as a text string and precompiled into assembly, but with its own semantics, with its own way of assigning variables, its own evaluation order, its own object system, and its own set of control structures. So no, it’s entirely its own language.

So there’s actually one entire extra language built into in AMOS?

Of course not. Two separate languages? That would be ridiculous.

There are three. Well, five if you count the pseudo-Assembly and the copper list code (which as mentioned earlier, will crash the computer if you try to use it under the compiler).

The third language is called Interface. It’s an entirely separate body of semantics for building and displaying windows and widgets. As for why there’s a separate system for interface widgets, guess what? The existing commands were too slow, so, well… they made an extra language. Because there’s not as if the operating system already contains perfectly suitable and fast code for a GUI, right?

And if you’re thinking that this could be something like MFC or wx, i.e. a graphical GUI creator with fit-to-purpose semantics, let me disabuse you of that right away. No, it’s just the same functions with different names and syntax, the only difference apparently is implementation. It’s like you’re hacking PhP in the days before there was PhP!

Structured programming (o cruelest joke!)

BASIC is often maligned, but the language family itself doesn’t preclude good structure. You could do a lot with very little. Something like duck typing would allow the creation of objects that could sensibly group related data, which could then be sent as function arguments.

But this is AMOS, where there’s no such thing as an object or a function argument. There are only integers, floats, strings and arrays, and naturally, they’re all of static length (without using its dodgy OS calling facility, you simply cannot reasonably use malloc from AMOS). And since the language is dynamically typed and variables are automatically instantiated, and since scope is something that only happens in procedures (which are so cumbersome as to preclude easy use)…

Yes, you guessed it: if you try to create a variable named x, let’s just hope you haven’t previously declared another variable called x somewhere in the program and forgot about it, because if you did, you’re now assigning a new value to that original variable, trashing it. Look forward to weird bugs, especially from the plethora of goto-like constructions (such as “every x gosub HELLO”, which will recall fond memories of the joys of debugging race conditions in C).

But there are functions which take arbitrary length input, however, such as polygon functions. You might even be forgiven for thinking we’ve finally stumbled into something sensible and useful. Alas, no — the number of arguments in those functions are set at compile time. That is, you can’t simply define an array of coordinates and then push it into the polyline function — no, you have to type out all the specific coordinates (“Polygon x(0), y(0) to x(1), y(1) to x(2), y(2) …”). Look forward to hilarious keyboard slips and the resultant bug hunt.

What it means is essentially that, contrary to languages like C in which you can raise the abstraction level by carefully encapsulating resultant functionality in functions and libraries, doing the same in AMOS quickly becomes a chore. The easier, more immediately productive choice is always to write it as one big blob of data, possibly with a few subroutines sharing data with the main function. Which boils down to the fact that while longer C programs can go toward greater order, longer AMOS programs naturally trend toward chaos and situational homicide.

It’s ironic to me that after learning rudimentary 68K Assembly, I already consider it far more well-formed and expressive than AMOS was, and AMOS was supposed to be instructive and easy to use!

But surely, if it was popular and skillfully coded, it couldn’t have been all bad!

To the contrary, I argue the greatest sin of AMOS was its popularity and the fact that it worked. A hated language would never have convinced so many young coders to waste their time in the vain effort of trying to learn AMOS well enough to write a proper game. A poorly written language without snazzy graphical features would have immediately dispelled the myth of its speed and power.

Instead, the fact that you could do some fairly cool things out of the box in AMOS concealed the fact that there was a cutoff point after that. Because try as it might, AMOS simply wasn’t capable of harnessing the full speed and capabilities of the Amiga.

To heap insult onto injury, learning the full scope of AMOS Pro was a full-time job easily comparable to the time it’d take learning Assembly. Only difference is, the AMOS programmer would end his journey realizing it was all smoke and mirrors, with few transferable skills that would make sense in other coding languages.

In closing, I admire Francois Lionet and co. They did a tremendous job on a project that clearly meant a lot to them, and obviously, a lot of Amiga fans disagree with me and loved their product.

Even so, I personally think that if there was ever any specific BASIC dialect Dijkstra alluded to when he said, “[..] students that have had a prior exposure to BASIC [..] are mentally mutilated beyond hope of regeneration.”, then surely it must have been a prescient reference to the coming of AMOS.

15/11/2016

Amiga Emulation 101

Hey everyone! I mentioned I've been working on an Amiga article. Sadly I got sidetracked: I had to upgrade to Windows 10, and found myself thwarted when moving my existing Amiga setup from the Linux laptop. I could have worked out the culprit (smart money's on memory corruption on the USB stick) but troubleshooting bores me to tears. I decided to make a new installation instead, with all the usual programs necessary for coding on the Amiga. At which point I realized, hey, someone other than me might find this useful.

So, in short, here's how to set up an easy-to-use Amiga 1200 desktop environment on either Linux or Windows.


Setting up the A1200

Ah, the trusty Amiga 1200. In my opinion, the 1200 sits closest to the sweet spot of the Amiga experience: faster than the 500, reasonably inexpensive to purchase, with four times the chip memory, gobs of expansion options and of course the AGA graphics. Back then, it was as if someone had taken the 500 and improved it across the board.

Of course, in hindsight, it wasn't a perfect machine. Blitter fill rates, sound quality, number of hardware sprites and floppy drive capacity hadn't kept pace with the other improvements. The AGA architecture, while more capable in certain areas, lacked the elegant, Swiss-watch interconnectedness of the OCS and ECS machines. Mostly, the 1200 was too little and too late, debuting half a decade after the point of being able to replicate the revolution that the original Amiga 1000 had been.

Nevertheless, the 1200 remains the easiest way to achieve a reasonable desktop experience on a low-end Amiga. Therefore, while the A500 or A2000 may be a "purer" way of experiencing the Amiga, this is not what we'll do in this instance. Instead, we'll emulate an Amiga 1200.

This tutorial has the following prerequisites:

  • a modern desktop, preferably running Windows 7/8/10 or Linux,
  • an internet connection, and
  • a ROM file of the A1200's kickstart chip (see below),
  • a full set of Workbench 3.1 floppy disks (or images thereof), and
  • snacks (optional).

The kick-rom (that is the kickstart file) is an image of the physical ROM chip that sits on the Amiga 1200 motherboard. The 1200 was originally released with version 3.0 of kickstart; the difference to 3.1 is fairly marginal and should not matter much for this tutorial. What does matter is that the emulation software we're going to use requires the kick-rom file to operate. Without that ROM file, the emulator will not run, and the ROM file is not free to distribute.

How to get a kick-rom file? Well, if you own a physical Amiga 1200 with access to Internet, you can download a program called GrabKick from Aminet. That will extract a file which you can then transfer to the PC.

The alternative is to buy the ROM from Cloanto, the current distributors. Their Amiga Forever package is a very good purchase; they offer various software and ROM packages as well as a complete easy to use Amiga environment at a very reasonable price. We're going to try a different approach to theirs for this tutorial, however, so if you buy their CD, don't bother installing the whole package.

FS-UAE

We're going to use an emulator, and when it comes to the Amiga, there's really only one: UAE. The acronym is commonly interpreted to mean Universal Amiga Emulator, but it originally stood for the Unusable Amiga Emulator, due to its inability to even boot. Further refinement provided the features theretofore missing. With the introduction of just-in-time compiling it got a hefty speed boost, and UAE today is fast enough to emulate Amigas with PowerPC accelerators and GPUs while still remaining cycle-exact.

UAE comes in different flavors, one of which is called FS-UAE. The FS part is the GUI built on top of UAE, and for my money it's a far more uncluttered and usable experience than WinUAE. As a bonus, it is available for major Linux flavors as well as Windows, and behaves identically between platforms. Download FS-UAE and install it according to these instructions (with the current version, you no longer need to edit the config files).

The first thing you need to do is to import the kickstarts. By clicking the top left icon, you will see a menu. Here, you either select Import Kickstarts... (if you extracted a free-standing kick-rom file) or Amiga Forever Import... if using Amiga Forever. Next, under Amiga Model, select A1200 and the appropriate ROM configuration (either 3.0 or 3.1/020 will do fine). Under Joystick & Mouse Port, select No Host Device for the joystick -- this will allow you to use the arrow keys when coding. Finally, register and save this as your configuration (left-hand list box).

Next, in the tab list, click on the tab icon that looks like a black chip. This takes you to the Kickstart ROM tab. Here, select Custom and choose your kick-rom file. You may also tick "Zorro II Fast RAM" - select the largest amount. Save configuration.

Now, click on the floppy icon in the tab list. This allows you to uncheck (and thus activate) all four potential floppy drives, which we will do for the sake of convenience. More important is the Media Swap List; FS-UAE requires you to add all floppies you can use beforehand. Click the plus sign, then select all the Workbench 3.x disks.

So far, we've set up a fairly standardized Amiga 1200 with some extra peripherals. However, there's one thing missing that we really need: a hard disk. Click the main menu (top left tab icon). From the menu, select HDF Creator... and create a non-partitioned HD file which you call System (a size of 60 MB should be enough). This creates a file that acts as a hard drive. Select the Hard Drives tab, and pick the file you just created.

Now, start FS-UAE with the Workbench disk in you primary floppy drive. Boot it up. You'll see your hard drive as an unformatted non-Dos disk. Click on it, select Format from the menu, using FFS (Fast File System) with no trash can. Format. Now, load the Install disk into DF1:, and Locale and Extras in the other two. Double-click on the Install disk, then on the Install Workbench icon. In the installer, select intermediate level, and when it comes to installation directory, select your System hard drive (for some stupid reason, the default is DF0:!). Installation should prompt you for disks as they are needed. Once you're done, Workbench 3.x will have been installed.

Configuring Workbench

The first thing you need to do is close down the Amiga. We need some way to get files onto the machine, and the easiest way is for you to mount a second hard drive under the hard drives tab. Instead of mounting a hard file, you can mount a Windows or Linux directory. I usually find it simplest just to mount the Downloads folder. Now you can freely move files between your main computer and onto the Amiga. Workbench will treat it as if it's a regular hard drive (as long as you select "show hidden files" from the menu).

Workbench is pretty well set up for serious work right off the bat, but there are a few things it lacks. Its greatest Achilles' Heel is arguably the lack of a decent command line interface. While the default CLI is leagues beyond MS-DOS, that's really damning with faint praise. To fix this, we're going to download KingCON (also known as Newshell) off of Aminet. KingCON is unfortunately packed in lha format. You can either use a free utility like 7-zip to open it up on the PC, or download Lha from Aminet. If you do the latter, move Lha.run to RAM:, execute the file there, then copy the archiver (called lha_68020) to the System:C/ folder. The other files are unnecessary.

Next, move KingCON_1.3 to RAM: and unpack it there. Execute the installer, and follow the instructions (basically, you enter the cli, type "ed s:user-startup", change KRAW and KCON to RAW and CON, and add the unmount CON: / unmount RAW: commands as it directs).

Slightly complicated? Perhaps. On balance, I think the new CLI (which lets you use the TAB key to autocomplete or choose files from inside a file requester) is easily worth the small hassle of installation.

Back up the hard-file; we're almost done.

Making it pretty (optional)

Workbench does look a bit drab. Nothing that can't be fixed, however -- all you need is to download Magic User Interface and MagicWB. Copy them to RAM: as usual, and then install.

Conclusion

You should now have an Amiga WB environment up and running. I've tried to keep my tutorial as general as possible, so I've avoided actual programming environments, DirOpus, graphics editors like DPaint, et cetera. There's a ton of useful software to that effect, and I'll mention others when needed.

This has been a primer on how to painlessly set up an emulated Amiga environment. I hope you liked it and will, as always, be grateful for feedback.

08/11/2016

On (Recursion (Recursion (Recursion ...

Hello everyone! I had an Amiga article all planned and ready, but since I couldn't make up my mind on the exact restrictions, I kept putting it off. Enough is enough. Now I found myself with a rather stream-of-conscious take on a common programming technique. To wit, it's about the use of recursion, and my struggle to make intuitive sense of it.

So, without further ado, here we go.

On recursion

The effective exploitation of his powers of abstraction must be regarded as one of the most vital activities of a competent programmer.
--Edsger W. Dijkstra

What's the best way to understand recursion? As the old joke has it, you must first learn recursion. Proponents of this technique claim it is an intuitively obvious, far-simpler way of iteration compared to the more popular imperative ones, and that it's only our mindset (maimed as it is by earlier exposure to imperative programming) that has us thinking otherwise.

Personally, I think that's a crock of shit. We all know recursion isn't simple, otherwise the joke would make no sense.

Holding up recursion as some sort of replacement for iteration is also bullshit. Loops are good. For-loops are okay. While-loops are good. All of them work in place of recursion, but that doesn't make them the same. They handle iteration differently. They have different strengths. They are separate idioms. And so, as in all programming, they require separate metaphors to be properly explained.

Now, it's no wonder that imperative programmers are used to while loops: it's built into our metaphor about how programs are supposed to execute. Recursion, though, requires us to revise our expectations. Loops are like a moving watch, with hands (numbers) that increase in proportion to each other, one sometimes triggering an alarm (a specific method call) or clicks over into a new state. So what makes a useful recursion metaphor?

Well... for me, recursion is all about what you see from where you are.

Traditional loops are flat. We see everything as one big field of similar items, or a big mass of numbers. All of these numbers are operated on by the loop, so we need to understand them and their interactions as a gestalt, as a whole. If we don't understand everything about the loop and the data on which it operates, the loop will at some point go off the rails. Those are a lot of factors for a programmer to juggle.

Recursion is different. In a proper recursive algorithm, your data is a structure, a grid. The shape of the grid doesn't really matter: all that matters is what happens on your immediate position on the grid. All you need to remember is that once you step one level up and down in the recursion, you are in effect moving along the grid. That's intrinsic to the structure, to the algorithm's idiom, so you don't need to keep track of it. All you need is to understand what happens at the specific point you occupy.

To me, where the metaphor of regular loop suggests enumeration, the metaphor of recursion suggests traversal. A regular loop chews through items on a level playing field. Recursion moves from node to node, like a spider flitting across a web. That makes recursion a natural fit for things that have tree-like behavior, but less ideal for things like iterating across flat containers. It also means the node is all you need to care about, which means less cognitive work.

Recursion can replace loops in a pinch, yes. By the same token, a wrench can do the work of a hammer. That doesn't make it the best tool for the job.

Perhaps I'm still poisoned by imperative thinking. It may be that Dijkstra, from whatever coder heaven he now resides, is even now shaking his head and muttering something about the irreparable damage of BASIC. Nevertheless, and this may sound paradoxical, I think recursion is even more useful if placed in constraints. And when it comes to coding, perhaps an abundance of metaphors isn't such a bad thing.

That's it for now. If you still have problems wrapping your head around recursion, I refer you to this article.

09/10/2016

Interactive Fiction with Inform 7

I like the idea of writing Interactive Fiction. If you're here, chances are that you do, too.

Today, there are many options for writing parser-based IF. I'm a C++ programmer by trade, but perhaps surprisingly, my tool of choice isn't the C-like TADS 3. Instead, I decided to learn Inform 7, where the code you write is essentially English.

This won't be an I7 tutorial. Several excellent ones already exist online, and there's also a book on the subject. Instead, I thought I'd list a few techniques that make I7 writing easier.

When a phrase might yield "nothing", always make it an object

It's a common pattern: you write a bit of code to pick out a specific object according to certain criteria. The problem is, sometimes there is no valid result. In that case, you want "nothing."

Your bedroom is a room. The house door is a door. It is west from the bedroom and east from the Garden. The house door is locked. The key is here. The key unlocks the house door.
The Lodestone Room is west of the Garden. 

The player carries the brass compass. The description of the brass compass is "The dial points quiveringly to the [magnetic direction]." 

To decide which direction is magnetic direction:
 decide on the best route from the location to the Lodestone Room, using even locked doors.

There's a problem here. When we reach the lodestone room, the compass will generate a runtime error, because nothing is of the wrong type: not a direction, but an object.

This is easy enough to fix: just make the return type of the phrase into an object.

Your bedroom is a room. The house door is a door. It is west from the bedroom and east from the Garden. The house door is locked. The key is here. The key unlocks the house door.
The Lodestone Room is west of the Garden. 

The player carries the brass compass. The description of the brass compass is "The dial [if the magnetic direction is nothing]spins and spins, not settling on any direction[otherwise]points quiveringly to the [magnetic direction][end if]." 

To decide which object is magnetic direction:
 decide on the best route from the location to the Lodestone Room, using even locked doors.
Of course, there are phrases that should never yield nothing. For such phrases, it's prudent to retain as much type information as possible.

On changing the auto-generated prose text for supporters

One of my pet peeves in Inform 7 comes up when I want to describe a room containing a supporter. When the supporter is empty, it's okay. The problem comes when the supporter holds something.
Moldavian Grouse
A grimy, dimly lit room. The air is heavy with cigarette smoke, lazily churned by the ceiling fans overhead.

You can see a bar (on which is a shot of fine whiskey) here.

>x bar
As old and sturdy as a fallen oak. 
On the bar is a shot of fine whiskey.
There are several interrelated and unrelated issues at play here. The first is the parenthesized part after mentioning the bar. In this case, that issue easily resolved by giving the bar an initial appearance. While that won't work for a portable supporter, it does us nicely here:

The Moldavian Grouse is a room. The printed name is "The Moldavian Grouse".

The description is "A grimy, dimly lit room. The air is heavy with cigarette smoke, lazily churned by the ceiling fans overhead."

The bar is a fixed in place supporter in the Moldavian Grouse. "In the center of the room is a large, old-fashioned bar." The description of the bar is "As old and sturdy as a fallen oak." On the bar is a shot of fine whiskey.
This raises a different problem, though: now there's a tacked-on message below the bar's initial appearance, saying "On the bar is a shot of fine whiskey." How do we change that?

The Moldavian Grouse is a room. The printed name is "The Moldavian Grouse".

The description is "A grimy, dimly lit room. The air is heavy with cigarette smoke, lazily churned by the ceiling fans overhead."
The bar is a fixed in place supporter in the Moldavian Grouse. "In the center of the room is a large, old-fashioned bar[if something is on the bar], [a list of things on the bar] atop it[end if]." The description of the bar is "As old and sturdy as a fallen oak." On the bar is a shot of fine whiskey.

Interestingly, that kills the supplementary "On the bar..." message!

There's no magic to it, though. What happens is that, by printing a list of things during the room description, Inform correctly deduces that we've mentioned them. A mentioned thing is not listed again (in fact, when it automatically enumerates things in the room, that Activity is actually named "listing unmentioned things").

However, there's still one remaining problem, the generic listing of items upon the supporter. Unlike the case with room description, that listing is not suppressed by mentioning the item beforehand. What's at work here is the examine supporters rule, which looks like this:

Carry out examining (this is the examine supporters rule):
 if the noun is a supporter:
  if something described which is not scenery is on the noun and something which is not the player is on the noun:
   say "On [the noun] " (A);
   list the contents of the noun, as a sentence, tersely, not listing concealed items, prefacing with is/are, including contents, giving brief inventory information;
   say ".";
   now examine text printed is true.

That rule is easy enough to turn off, like so:

The Moldavian Grouse is a room. The printed name is "The Moldavian Grouse".

The description is "A grimy, dimly lit room. The air is heavy with cigarette smoke, lazily churned by the ceiling fans overhead."

The bar is a fixed in place supporter in the Moldavian Grouse. "In the center of the room is a large, old-fashioned bar[if something is on the bar], [a list of things on the bar] atop it[end if]." The description of the bar is "As old and sturdy as a fallen oak[if there is something on the bar], holding [the list of things on the bar][end if]." On the bar is a shot of fine whiskey.

The examine supporters rule does nothing when examining the bar.

Of course, this also lists scenery items, and it would also list the player should the player be on the bar. In this instance though, the above is perfectly adequate.

The going action allows two prepositions, both useful

This one is short and sweet. Not too long ago, I was told of a particular turn of phrase with useful properties. This is about the going action. Consider the following:

The Shadowy Forest is a room. "Gloomy pine trees surround you in the gathering mist. The haze makes it difficult to see clearly, although you can just about make out a sloping trail to the west."
The Brook Clearing is west of the Forest. "A merry brook winds its way through the turf here."

Instead of going nowhere, say "You'd just get lost."
Instead of going up in location, say "There's no way you could climb, given your back problems."

How does this work? Well, there are a few prepositions bound to the going action. First, it's "going [direction] from" and "going [direction] to". These refer to the action of going a valid direction. Then, there's "going nowhere", which refers to going (but failing to go) in any invalid direction.

Both of these wholly depend on whether the direction is valid or not. But sometimes, you don't want to do that; sometimes, you want to intercept the mere attempt to go in a given direction (no matter if it's a valid one or no). For that purpose, you can use the "going [direction] in" construction.



That concludes my first Inform 7 piece. Thank you for reading. Although I hope this post was useful, it may need improvement, and any feedback you could give would be much appreciated.