This post is part of an ongoing series about Affordances and Programming Languages.

Many programming languages provide support for reflection, which allows for very creative metaprogramming when solving problems. The reflection facilities in various languages differ in the kinds of features they provide, their ease of use, and their verbosity.

Reflection is a kind of affordance.

Reflection is often used to implement the Factory Pattern. As an example, consider an application that receives commands over a socket. Each command takes a different set of arguments and performs some more or less complex action in response. This example was inspired by John Pignata’s excellent talk at Mountain West Ruby Conference 2013, Code Smells: Your Refactoring Cheat Codes.

Assuming that each command has been encapsulated into its own subclass of Command, the obvious solution is to dispatch commands with a case statement.

Note that C++ doesn’t allow strings as case options in a switch statement, so we’re forced to use a series of if statements instead. This is also a kind of affordance.

Dispatch with Case Statement
std::unique_ptr<Command> command;
if (commandToken == "PING")
{
command.reset(new Ping);
}
else if (commandToken == "SEND")
{
command.reset(new Send);
}
...
else
{
throw CommandNotFound(commandToken);
}
command->execute(arguments);

Every time we add a new command, we have to update this if statement. Since C++ only has minimal reflection capabilities, we might choose to stop there, or we might introduce some kind of command registry using macros or explicit initialization.

In Ruby, since we have reflection and metaprogramming facilities, we can come up with something a little more maintainable:

Ruby Dispatcher
module Commands
COMMANDS = {
"PING" => Ping,
"SEND" => Send,
...
}
def self.dispatch(command_token, arguments)
klass = COMMANDS[command_token] || raise CommandNotFound.new(command_token)
klass.new.execute(arguments)
end
end

Now, adding a new command is as simple as adding one more entry in the COMMANDS hash.

In Ruby, superclasses don’t know about their subclasses by default. This is not true of Smalltalk, though, so we can take advantage of that:

Smalltalk Dispatcher
Command class>>dispatch: aString arguments: anArray
class = self allSubclasses
detect: [:each | each token = aString]
ifNone: [(CommandNotFound command: aString) raise].
class new execute: anArray
Command class>>token
^self subclassResponsibility
Ping class>>token
^'PING'
Send class>>token
^'SEND'

By taking advantage of Smalltalk’s reflection, we can completely eliminate any central registry of commands. Now, adding a new command is as simple as introducing a new Command subclass. As long as the new class inherits from Command and implements the class-side token method, it will automatically be found by the dispatcher.

It is possible to implement a similar approach in Ruby using Class#inherited, but that’s a bit more work to set up.

And that’s actually the point of affordances. Because Smalltalk provides direct access to subclasses, it affords the ability to find the commands dynamically. Because Ruby and Smalltalk provide reflection, they afford a cleaner implementation of the factory pattern than languages without reflection.