Inspired by Swift

Gulliver meets the Oopers

Lemuel Gulliver’s world was black. No light, no sound, infinite darkness and solitude. Am I dead?, he asked himself. No, surely not. He opened his eyes.

Still, everything remained black. My God, I am dead! Lemuel Gulliver began to panic. Then, slowly, he realised that panicking itself meant life: My heart is pounding, he thought, therefore it must be beating. Life! Sweet, God-given, beautiful life! But what sort of life is it, to live as a man dead?

Memory failed him but in bursts, though those bursts helped him understand his predicament. Yes, a shipwreck. But he had got into a lifeboat, which had carried him precariously through the swell of the storm.

Of course, the lifeboat! Gulliver raised his hand, and laughed loudly to himself as it hit the planks. He was on land, and it was the upturned lifeboat had given the impression of his premature trip to Hades. He pushed with all of his strength, and shifted the boat over to lie beside him on the beach.

For minutes he lay still. His eyes needed to adjust, his arms to recover, and his mind to regain some composure. Once the blackness of the lifeboat and the whiteness of the sudden return to light had begun to balance, he appraised his condition. It was indeed a beach upon which he lay, marked with dunes and occasional tufts of a tall grassy plant. The water, which apparently had once been turbulent enough to deposit his unconscious self along with its inverted boat some way up the beach, now was smooth and still.

To his right, behind one of the dunes, he could make out rooves denoting that a settlement was not far away. One in particular, a great grey spire, stood out like a flagstaff. Realising that he needed water, food and assistance, Gulliver uneasily got up and started walking toward the town.

As he crested the dune he became aware of another walker, making her way along a path that would bring her closer and heading like him in the direction of the town. He got to the path and waited for her to approach.

“Hello, madam, I don’t mean to burden you but find myself in innumerable difficulties. I’m a traveller who has got himself shipwrecked in this country, and who finds himself in need of water, provisions and other assistance. Can you help me?”

The woman stopped, smiled at him, then executed a perfect curtsey before she replied. “Good day to you, sir, and is not the weather fine? My name is Kaye Allen, delighted to meet you. I’m sorry to hear about your problems and certainly want to help, please come with me to our home, where my husband and I will feed you and lodge you while you make your arrangements.”

Gulliver introduced himself and thanked her heartily for her generosity. Together they walked towards the town, the flagstaff spire always ahead of them. Kaye Allen was engrossed during much of the walk in the task of writing postcards: many of them addressed to different people each containing short messages. Gulliver asked about the spire, and she answered but not before finishing the current postcard, and packing away it and her pen.

“It is best that you not inquire about such things, sir. That building is associated with immorality and debasement, and it would not be becoming for an Ooper to associate with the sort found there.”

“An Ooper, madam? Pardon me but I have never encountered that word before. What is an Ooper?”

“Why, Mr. Gulliver, I am an Ooper, my husband is an Ooper, and indeed our whole community is comprised of Oopers. It is our religion, our philosophy, and our way of life. But let us not talk of that now. There will be time enough later. Let us now make our way onward, the afternoon draws on.”

The rest of their walk to the Allens’ house was mostly without event, though once a man approached them to ask the time. Gulliver thought there was something odd about Mrs. Allen’s reply, though he could not determine what it was as it seemed polite enough. She stopped, smiled at the man, then executed a perfect curtsey before she replied. “Good day to you, sir, and is not the weather fine? My name is Kaye Allen, delighted to meet you. I believe the time to be something after five of the clock, see the sun already begins to set.”

As the twilight drew in they arrived at last at the house. Kaye’s husband was already in, and he greeted Gulliver warmly. He smiled, then executed a perfect bow before saying “Good day to you, sir, and is not the weather fine? My name is Turmo Allen, delighted to meet you. Please, find the wash room upstairs and feel welcome to borrow some clothes, while we prepare dinner.”

Gulliver felt better for a wash and a change of clothes, but not so much improved as he did when they sat down to eat. While the food was simple, it was plentiful and he had no conception of how long it was since he had last eaten. The Allens were very precise about setting the table. Before each dish was served, the fork would be placed on the left of the setting just so. Then the knife to the right, just so. Then the water glass, just so, and filled with water from the pitcher, just so. Finally the dish was brought, placed just so in the centre of the setting, and they would sit, pick up first the fork then the knife, and begin eating.

Gulliver asked about this Oopers religion that Kaye had mentioned, and found Turmo to be most effusive on the topic.

“We Oopers live our lives according to the books of the lady Adele of the golden mountain. The legends say that many centuries ago, before the Oopers, the people of this region were simple backwards folk who believed strongly in superstition. They spent their time in constructing procedures for each other to follow, such procedures becoming more baroque and complicated with time. Even in emergencies and when under attack, if they had begun one of their procedures then needs must it be finished.

“One day, so we are told, a hot air balloon of many colours landed in the market place of this very town. The occupants declared themselves to be emissaries of a wonderful place, a tall tower of ivory on an island far away. They said that they too had previously been enslaved by their procedures, but that they had freed themselves through enlightenment and that they could teach this freedom to our forebears.

“One of their number was the lady Adele of the golden mountain, and it is she who wrote their teachings in the books that have come down through the generations, yea even to us, and taught us the lessons of these people of the balloon. You have seen my wife, Kaye, writing many postcards for her correspondents both near and far?”

“Why, Mr. Gulliver, I have even written one for you.”

“The people of the balloon taught us that complex procedures can be avoided, and our community can function together better, if we instead send each other messages. Our whole philosophy and way of life is based on this message-sending. It has delivered us from the oppression of our procedures, enlightened our society, and advanced us immeasurably.”

Gulliver interrupted at this point. “Thank you, sir, for your most edifying explanation, and thank you madam for your message. May I read it?”

Mrs. Allen laughed. “That would not do at all, Mr. Gulliver! Due process must be observed. See, I have gathered all of the cards that I have written so far today. Tomorrow morning I will take them to the post office, and there they will be despatched to their recipients. Including you! Once you have formally received your card, then you may read your message. Not before!”

“But is that not an example of the sort of procedure you say belonged to the simple times of your forebears? Is that not unnecessarily convoluted and slow, as you could simply tell me the message now or give me the card?”

“No, sir, it is not. We Oopers have done away with the procedure, and replaced it with this simple act of message sending.”

“Then why not give me your message now?”

“That would not do at all, Mr. Gulliver! Due process must be observed.”

Gulliver could sense his own frustration mounting, and thought it prudent to change the subject. Unfortunately in his haste he forgot Mrs. Allen’s reaction to his previous enquiries regarding the spire, and that is the topic to which he next turned.

“It is best for you if you avoid that place, sir,” Mr. Allen quickly responded. “It is a Church, a building associated with the debased Phuncers and their heretical acts. No true Ooper would go there, and it would not do for you to be tainted by their evil ways. Now let us talk no more of them.”

Gulliver recognised that he was not being the most gracious or entertaining of guests, so did not suggest any further metiere for their conversation. In the absence of his conversational selections there was nothing for the Allens to respond to, so the rest of the dinner proceeded in silence until they all departed to bed.

Escaping to the Phuncers

Morning breakfast passed much as evening dinner had. While the Allens were polite enough, Gulliver found it infuriating to deal not only with their strange, repetitive rituals but also with their insistence that they had left such procedure behind. He quizzed them upon this topic.

“You say that the Oopers have freed themselves from the shackles of procedure, yet I observe you both greet me using exactly the same set of rules. Do you not see that this itself is procedure?”

“No, sir, you miss the subtlety that was taught by Adele of the golden mountain. See, while we each say an identical greeting to you, my husband bows before doing it while my action is to curtsey. All people say the greeting, but specifically those people who are men perform a bow while those people who are women perform a curtsey. This ability to make more specific amendments is what liberated the Oopers.”

“But still, all you are doing is executing this procedure!”

“I wish, sir, that I had more time to discuss this with you. But now I must attend to my messages.”

With that, Kaye Allen returned to her postcards and Lemuel Gulliver, with more civility and politeness than he felt, thanked her for the hospitality he had received which in fact had been generous and left their abode hastily. His aim was to discover his location and how he might return home.

Once he was outside, his eyes were once again drawn to that strange spire, the Church by which his hosts had been so repulsed. Perhaps here he would find some useful information, or at least a different insight into this unique land. Resolved to learn more, he set out in the direction of the Church.

As he walked the mile or so to the tall building, he saw plenty of Oopers, recognised by their strange rituals and their stacks of message cards. The closer he came to his goal, however, the thinner their numbers, and when he finally arrived at the huge quadrangle outside the Church there was not one Ooper to be seen.

That is not to say that the square was empty, but clearly the people here were of a different background. They were gathered into groups, usually comprising four to six people, who criss-crossed the square purposefully in files. Perhaps these were the Phuncers he had been told about. Gulliver proceeded toward the Church to learn more.

Outwardly, the Church reminded him in passing of some of the religious institutions he remembered from his home. Indeed where his own house of prayer signed its identity with the Greek letters alpha and omega, this Church even had a similar symbol: the letter lambda. Confident that he was on somewhat familiar territory, he entered.

Gulliver started when, just inside the doorway before his eyes had adjusted to the gloom, he almost bumped into a file of a half dozen people who were on their way out. He mumbled an apology, then introduced himself.

“My name is Lemuel Gulliver, what is your name please?” If the lead person in the file heard him, she did not make it evident. She consulted a clipboard she was holding, made a note on it, then whispered something to the second person in the file. He did the same, and so on down the line. Finally the person at the back checked his clipboard, made a note, and replied “How do you do? My name is Alonso.”

Gulliver was not certain what had just happened. Perhaps the woman to whom he had addressed himself had not heard him clearly. He cleared his throat, and repeated: “My name is Lemuel Gulliver, what is your name please?” Again, she looked at her clipboard. This time, though, she apparently saw something that satisfied her (Gulliver could not be certain, but he thought she was looking at the note she had just made moments earlier) and showed that to the man behind her. He, in his turn, found the corresponding note on his board and showed it to the third. As before, it was the last of them who replied “How do you do? My name is Alonso.”

While this was happening, Gulliver had been able to take a look at the lead woman’s board. It was full of fragments of conversations, the left column apparently representing sentences that had been uttered to her (see! There is the very greeting I introduced myself with, written at the end of the page!) and so he guessed that the second column was the list of responses she had passed on to her colleague. Gulliver surmised that this tally represented an efficiency of sorts: by remembering all of her previous discussions, she could show her friends the answers she had previously given without having to construct them anew.

Conversation was, understandably, engaged at a slow pace. All the while Gulliver addressed himself to the woman at the front of the file; all the while she passed the discussion back through the chain of six; all the while Alonso (he assumed that this name referred to the ultimate member of the group) issued the responses.

“Tell me, is this the place of the Phuncers?”

“Why yes, this Church is our holy building, and you are welcome within it.”

“I hope to learn something of your people. Why is it that you carry on in these files?”

“One of the oldest tenets of the Phuncer creed is that a person has more capability as a member of a group than as an individual. By composing our different abilities we become more efficient.”

“I see, that is an interesting philosophy. When did it arise?”

Here, an interesting modification to the usual process occurred. As before, the question was passed back through the file and the notes were made, but the fourth person made a record, then put their board down, picked it up anew and read back that note. Making another, they repeated the process. And again. (Gulliver could just about see the board, and it seemed that they had written the symbols “1 +” over and over.) Finally satisfied, they passed the whisper on again until Alonso could give a response.

“It was six decades ago that our movement came into being.”

“What was the purpose behind its creation?”

“Back before we were liberated, the people of this part were oppressed by a government that forced people into performing all manner of complicated and perverse rituals and procedures. Our forebears sought to free us from these procedures, from the imperatives coming from the State.”

“And is your number many?” (Again, the repeated setting and resetting of the clipboard.)

“When first we started we were few. We formed a commune that sought to minimise State interference within its boundaries, and to achieve self-sufficience. Recently our number has become bolstered, and even those among the heathen Oopers have joined us and learned from our teachings.”

“And has this surge in membership changed your position?”

“We are now so numerous that our whole conception has changed. Rather than seeking to reduce interaction with the State, we intend to overthrow it completely. Yea, anarchy! But not the chaos that you may associate with it. Compositions of individuals each performing their prescribed function can yield a higher order.”

This last response had taken longer than usual for the group to formulate. Whereas before they had communicated with each other, one after the other, in building their response, they had needed outside help here. One of their file broke rank, and went out from the Church into the square. There, Gulliver saw that he approached a besuited woman, greeted her politely, then a complicated exchange of handshakes, papers and stamps ensued. When this procedure was complete he discussed something (Gulliver assumed the current conversation between himself and Alonso’s group) with her a while. On concluding this business he raised his hat, returned to the file and continued the whisper game.

“Who was that person with whom your colleague discoursed then?”

“She is a civil servant. We occasionally need to engage their help in carrying on our business.”

“You mean she represents the State?”

“Yes, quite so. They can be very helpful in our achievement of our aims.”

“But didn’t you say that you were planning to replace the State?”

“Planning? Yea, it is our very destiny! All trappings of State will be dissolved and a functional order, a higher order, will take its place.”

At this, Gulliver realised that he was not getting much further than in his discussions with the Oopers previously. He bade his interlocutors farewell, and returned to the square.

All around, he saw the Phuncers, and all around, they reminded him very much of the procedures that they, as the Oopers, claimed to have left behind. The way they followed each other around in files. The recording previous discussions in their clipboards. The convoluted discussions with civil servants.

They shared other traits with the Oopers: their claim that they had moved beyond the things that they still actually practiced every day, and the complete refusal to accept nor even see that this was the case. This gave Gulliver a start: maybe there was something both groups had in common, some shared memory that accounted for their commonalities? He had to find out more.

Gulliver unravels

As Gulliver pondered this strange town and its inhabitants, he found himself back in Ooper territory. This was unsurprising as there were many more Oopers than Phuncers that he had seen since his shipwreck. He also realised that he was at the University, with the buildings somewhat coarsely modeled on the ivory tower that the Allens had described to him. This presented perhaps the best opportunity he had to understand this place. He looked for signs and campus maps, and eventually located the library.

Realising that there were political implications to his research, he asked the librarian for the writings of Adele of the golden mountain and associated criticisms and commentaries. She happily met his greeting (a curtsey, then “Good day to you, sir, and is not the weather fine?”), went away and brought back a whole stack of books which he took to his desk. There were the books by Adele herself, and contemporary discussions such as “Oopism: An Evolutionary Approach” (some wag of a student had subtitled this “On the Origin of Classes by Means of Artificial Selection”) and Bertrand de la Tour’s “Oopist Construction”, which seemed to have been written by a contract lawyer. There were also more modern interpretations of the earlier texts, such as Cecil R. Martin’s “Clean Living” and “Clean Liver”.

But this was not enough to satiate Gulliver’s curiosity. Once the librarian had returned to her postcards, he paged through the catalogue to try and find anything on the Phuncers and their foundation. There was nothing explicit, but “Religion: Heresies” and “Politics: Anarchy” seemed appropriate places to look. He soon discovered a couple of likely tomes: “The Structure and Interpretation of Careful Phuncism” and “Concepts in Political Languages”.

And so Gulliver read. There was to much to read in one sitting, but he also didn’t want to risk the Ooper librarian seeing all of his material. He hid books behind shelves, rushed out to the University’s refectory to get a brief meal and slept in a corner of the campus. For three days he read, living like a hybrid of a hermit and a monk.

The more he read, the more he was shocked: he was reading the same thing in two different places! Each collection of material described the problems that had beset the town when the focus had been on procedures, and lay out a manifesto for moving beyond this situation. Each manifesto was broadly the same: break the procedures into focussed skills; find individuals who are good at those skills and give them the single responsibility of working in that skilled area; compose teams that can more efficiently complete large tasks by combining their skill areas.

At some point, then, the two had declared a holy war. Each knew that their own approach was correct and the other was heretical. But what was the source of their disagreement? Gulliver thought back to a previous encounter, in which two peoples considered each other mortal enemies due to their choice of which end of a boiled egg to eat first. At least, he thought to himself, those people disagreed on something.

Posted in Uncategorized | Leave a comment

Fun and games (with rewritten rules) in Objective-C

An object-oriented programming environment is not a set of rules. Programs do not need to be constructed according to the rules supplied by the environment. An object-oriented environment includes tools for constructing new rules, and programs can use these to good effect. Let’s build multiple method inheritance for Objective-C, to see a new set of rules.

The goal

Given three classes, A, B, and C:

@interface A : NSObject

-(NSInteger)a;
-(NSInteger)double:(NSInteger)n;

@end

@implementation A

-(NSInteger)a { return [self double:6]; }

@end

@interface B : NSObject

-(NSInteger)b;

@end

@implementation B

-(NSInteger)b { return 30; }

@end

@interface C : NSObject

-c;

@end

@implementation C

-(NSInteger)double:(NSInteger)a
{
  return a*2;
}

-c { return @([self a] + [self b]); }

@end

We want to find the value of a C instance’s c property. That depends on its values of a and b, but that class doesn’t have those methods. We should add them.

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    C *c = [C new];
    [c addSuperclass:[A class]];
    [c addSuperclass:[B class]];
    NSLog(@"The answer is %@", c.c);
  }
}

We want the following output:

2015-02-17 20:23:36.810 Mixins[59019:418112] The answer is 42

Find a method from any superclass

Clearly there’s some chicanery going on here. I’ve changed the rules: methods are no longer simply being looked up in a single class. My instance of C has three superclasses: A, B and NSObject.

@interface NSObject (Mixable)

- (void)addSuperclass:(Class)aSuperclass;

@end

@implementation NSObject (Mixable)

-superclasses
{
  return objc_getAssociatedObject(self, "superclasses");
}

- (void)addSuperclass:(Class)aSuperclass
{
  id superclasses = [self superclasses]?:@[];
  id newSupers = [superclasses arrayByAddingObject:aSuperclass];
  objc_setAssociatedObject(self, "superclasses", newSupers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (Class)superclassForSelector:(SEL)aSelector
{
  __block Class potentialSuperclass = Nil;
  [[self superclasses] enumerateObjectsUsingBlock:^(Class aClass, NSUInteger idx, BOOL *stop) {
    if ([aClass instancesRespondToSelector:aSelector])
    {
      potentialSuperclass = aClass;
      *stop = YES;
    }
  }];
  return potentialSuperclass;
}

- (NSMethodSignature *)original_methodSignatureForSelector:(SEL)aSelector
{
  NSMethodSignature *signature = [self original_methodSignatureForSelector:aSelector];
  if (signature)
  {
    return signature;
  }
  Class potentialSuperclass = [self superclassForSelector:aSelector];
  return [potentialSuperclass instanceMethodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
  SEL aSelector = [anInvocation selector];
  Class potentialSuperclass = [self superclassForSelector:aSelector];
  [anInvocation invokeSuperImplementation:potentialSuperclass];
}

+ (void)load
{
  if (self == [NSObject class])
  {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(original_methodSignatureForSelector:)),
                                   class_getInstanceMethod(self, @selector(methodSignatureForSelector:)));
  }
}

@end

Now invoke that method.

When you write [super foo], the Objective-C runtime needs to send a message to your object but tell the resolution machinery to look at the superclass for the method implementation, not at the current class. It uses a function objc_msgSendSuper to do this. In this case, I don’t have the superclass: I have a superclass, one of potentially many. So what I need to do is more general than what messaging super does.

Luckily for me, objc_msgSendSuper is already sufficiently general. It receives a pointer to self, just like the usual objc_msgSend, but in addition it receives a pointer to the class to be used as the superclass. By controlling that class pointer, I can tell the system which superclass to use.

A category on NSInvocation calls objc_msgSendSuper with the appropriate arguments to get the correct method from the correct class. But how can it call the function correctly? Objective-C messages could receive any number of arguments of any type, and return a value of any type. Constructing a function call when the parameters are discovered at runtime is the job of libffi, which is used here (not shown: a simple, if boring, map of Objective-C value encodings to libffi type descriptions).

@interface NSInvocation (SuperInvoke)

-(void)invokeSuperImplementation:(Class)superclass;

@end

@implementation NSInvocation (SuperInvoke)

- (BOOL)isVoidReturn
{
  return (strcmp([[self methodSignature] methodReturnType], "v") == 0);
}

-(void)invokeSuperImplementation:(Class)superclass
{
  NSMethodSignature *signature = [self methodSignature];
  if (superclass)
  {
    struct objc_super super_class = { .receiver = [self target],
      .super_class = superclass };
    struct objc_super *superPointer = &super_class;
    ffi_cif callInterface;
    NSUInteger argsCount = [signature numberOfArguments];
    ffi_type **args = malloc(sizeof(ffi_type *) * argsCount);
    for (int i = 0; i < argsCount; i++) {
      args[i] = [self ffiTypeForObjCType:[signature getArgumentTypeAtIndex:i]];
    }
    ffi_type *returnType;
    if ([self isVoidReturn]) {
      returnType = &ffi_type_void;
    }
    else {
      returnType = [self ffiTypeForObjCType:[signature methodReturnType]];
    }
    ffi_status status = ffi_prep_cif(&callInterface,
                                     FFI_DEFAULT_ABI,
                                     (unsigned int)[signature numberOfArguments],
                                     returnType,
                                     args);
    if (status != FFI_OK) {
      NSLog(@"I can't make an FFI frame");
      free(args);
      return;
    }

    void *argsBuffer = malloc([signature frameLength]);
    int cursor = 0;
    cursor += args[0]->size;
    void **values = malloc([signature numberOfArguments] * sizeof(void  *));
    values[0] = &superPointer;

    for (int i = 1; i < [signature numberOfArguments]; i++) {
      values[i] = (argsBuffer + cursor);
      [self getArgument:values[i] atIndex:i];
      cursor += args[i]->size;
    }
    if ([self isVoidReturn]) {
      ffi_call(&callInterface, objc_msgSendSuper, NULL, values);
    } else {
      void *result = malloc(returnType->size);
      ffi_call(&callInterface, objc_msgSendSuper, result, values);
      [self setReturnValue:result];
      free(result);
    }
    free(args);
    free(values);
    free(argsBuffer);
  }
}

@end

Conclusion

You’ve seen this conclusion before: blah blah awesome power of the runtime. It doesn’t just let you do expressive things in the Objective-C game, it lets you define a better game.

Posted in code-level, OOP | Leave a comment

Objective-Curry

Sadly it’s not called Schoenfinkeling, but that’s the name of the
person who noticed that there’s no reason to ever have a function with
more than one argument. What you think is a function with two
arguments is actually a function with one argument that returns a
function with one argument, this second function closing over the
first argument and acting perhaps on both.

This is, of course, famed for its application (pardon the pun) to Object-Oriented
Programming. We can take a class like this:

@interface NamePrinter : Curryable

- (void)printFirstName:(NSString *)first surname:(NSString *)last;
- (void)printFirstName:(NSString *)first age:(NSInteger)age;
- (void)printFirstName:(NSString *)first middle:(NSString *)middle surname:(NSString *)last;

@end

and use it like this:

int main(int argc, char *argv[]) {
  @autoreleasepool {
    id printer = [[NamePrinter new] autorelease];
    id curried = [printer printFirstName:@"Graham"];
    [curried surname:@"Lee"];
    [curried surname:@"Greene"];
    [curried surname:@"Garden"];
    [curried age:18];

    id alex = [printer printFirstName:@"Alexander"];
    id alexG = [alex middle:@"Graham"];
    [alexG surname:@"Bell"];
  }
}

(your compiler probably complains at this point that it doesn’t know
what you’re up to. Of course, you know better.)

We’ll get results like this:

2015-02-13 00:57:57.421 CurrySauce[41877:134228] Graham Lee
2015-02-13 00:57:57.421 CurrySauce[41877:134228] Graham Greene
2015-02-13 00:57:57.421 CurrySauce[41877:134228] Graham Garden
2015-02-13 00:57:57.422 CurrySauce[41877:134228] Graham is 18 years old
2015-02-13 00:57:57.422 CurrySauce[41877:134228] Alexander Graham Bell

OK, we don’t actually get that for free. There’s some secret sauce I
haven’t shown you: secret curry sauce.

Here be dragons

As with
all the best bits of Objective-C,
you need to turn off the automatic reference counting to do what
follows (you’ll have already seen a call to -autorelease above). ARC
works wonders when you try to write Java in Objective-C, give or take
the strong-weak-strong tango. It isn’t so helpful when you try to
write Objective-C in Objective-C.

Partial application

The NamePrinter class knows that you might call it with a partial
application, so it checks whether the selector you sent in your
message matches the prefix of any method it knows. If it does, and the
return type and argument types in this prefix can be uniquely
determined, then it creates a proxy to listen for the rest of the
application.

The restrictions on types are there due to the way that Objective-C
deals with C types in message sending. It’d be a lot easier to do this
in Ruby or Smalltalk, where everything is an object reference: as
Objective-C needs to deal with C types of different sizes, you must be
able to construct a single invocation from the prefix selector.

int argumentsForSelector(SEL aSelector)
{
  const char *name = sel_getName(aSelector);
  int count = 0;
  while(*name != '\0') {
    if (*name++ == ':') {
      count++;
    }
  }
  return count;
}

@implementation Curryable

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
  NSMethodSignature *superSignature = [super methodSignatureForSelector:aSelector];
  if (superSignature) {
    return superSignature;
  }
  NSString *thisSelectorName = NSStringFromSelector(aSelector);
  NSMutableSet *signatures = [NSMutableSet set];
  int argCount = argumentsForSelector(aSelector);
  Class currentClass = [self class];
  while (currentClass != Nil) {
    unsigned int methodCount = 0;
    Method *methodList = class_copyMethodList(currentClass, &methodCount);
    for (int i = 0; i < methodCount; i++) {
      Method method = methodList[i];
      SEL anotherSelector = method_getName(method);
      NSString *selectorName = NSStringFromSelector(anotherSelector);
      if ([selectorName hasPrefix:thisSelectorName]) {
        NSMethodSignature *fullSignature = [self methodSignatureForSelector:anotherSelector];
        NSMutableString *constructedTypeSignature = [[@"@@:" mutableCopy] autorelease];
        for (int j = 2; j < argCount + 2; j++) {
          [constructedTypeSignature appendString:@([fullSignature getArgumentTypeAtIndex:j])];
        }
        [signatures addObject:[[constructedTypeSignature copy] autorelease]];
      }
    }
    free(methodList);
    currentClass = class_getSuperclass(currentClass);
  }
  if ([signatures count] != 1) {
    NSLog(@"curried selector does not uniquely match the type of any full selector prefix");
    return nil;
  }
  return [NSMethodSignature signatureWithObjCTypes:[[signatures anyObject] UTF8String]];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
  id curry = [CurrySauce curryTarget:self invocation:anInvocation];
  [anInvocation setReturnValue:&curry];
}

@end

All of that, just to return a proxy object.

Finish the application

This proxy also responds to unknown selectors, by trying to tack
them onto the end of the partially-applied selector. If that works,
and it ends up with a selector that the target recognises, then it
constructs the combined invocation, copies the arguments from the two
partial invocations, and invokes it on the target. If the combined
selector is supposed to return something then this proxy unpacks the
return value and puts it into the invocation it received, to ensure
that the caller picks it up.

SEL concatenateSelectors(SEL firstSelector, SEL secondSelector)
{
  NSString *firstPart = NSStringFromSelector(firstSelector);
  NSString *selectorName = [firstPart stringByAppendingString:NSStringFromSelector(secondSelector)];
  return NSSelectorFromString(selectorName);
}

@implementation CurrySauce
{
  id target;
  NSInvocation *invocation;
}

-initWithTarget:object invocation:(NSInvocation *)partialApplication
{
  target = [object retain];
  invocation = [partialApplication retain];
  return self;
}

+curryTarget:object invocation:(NSInvocation *)partialApplication
{
  return [[[self alloc] initWithTarget:object invocation:partialApplication] autorelease];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
  //special case for respondsToSelector
  if (aSelector == @selector(respondsToSelector:)) {
    return [target methodSignatureForSelector:aSelector];
  }
  SEL combinedSelector = concatenateSelectors([invocation selector], aSelector);
  NSMethodSignature *combinedSignature = [target methodSignatureForSelector:combinedSelector];
  if (combinedSignature != nil) {
    NSMutableString *completionType = [NSMutableString stringWithFormat:@"%s@:",[combinedSignature methodReturnType]];
    for (int i = argumentsForSelector([invocation selector]) + 2; i < argumentsForSelector(combinedSelector) + 2; i++) {
      [completionType appendFormat:@"%s",[combinedSignature getArgumentTypeAtIndex:i]];
    }
    return [NSMethodSignature signatureWithObjCTypes:[completionType UTF8String]];
  } else {
    return nil;
  }
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
  if ([anInvocation selector] == @selector(respondsToSelector:)) {
    [anInvocation invokeWithTarget:target];
    return;
  }
  SEL realSelector = concatenateSelectors([invocation selector], [anInvocation selector]);
  NSMethodSignature *signature = [target methodSignatureForSelector:realSelector];
  NSInvocation *combined = [NSInvocation invocationWithMethodSignature:signature];
  int argumentToSet = 2;
  void *argBuffer = malloc([[invocation methodSignature] frameLength]);
  for (int i = 2; i < [[invocation methodSignature] numberOfArguments]; i++) {
    [invocation getArgument:argBuffer atIndex:i];
    [combined setArgument:argBuffer atIndex:argumentToSet++];
  }
  free(argBuffer);
  argBuffer = malloc([[anInvocation methodSignature] frameLength]);
  for (int i = 2; i < [[anInvocation methodSignature] numberOfArguments]; i++) {
    [anInvocation getArgument:argBuffer atIndex:i];
    [combined setArgument:argBuffer atIndex:argumentToSet++];
  }
  free(argBuffer);

  [combined setTarget:target];
  [combined setSelector:realSelector];
  [combined invoke];
  if (strcmp([[combined methodSignature] methodReturnType], "v")) {
    void *returnBuffer = malloc([[combined methodSignature] methodReturnLength]);
    [combined getReturnValue:returnBuffer];
    [anInvocation setReturnValue:returnBuffer];
    free(returnBuffer);
  }
}

- (void)dealloc
{
  [target release];
  [invocation release];
  [super dealloc];
}

@end

Conclusion

Blah blah awesome power of the runtime, I suppose. It’s pretty cool
that you can do this sort of thing in 150 lines of ObjC. I doubt many
people would want to use it for reals though.

Posted in code-level, Foundation, OOP | 1 Comment

A subtle [mis]understanding of monads

As I said when talking about Learning Phases, one of the things that happens when I’m trying to learn a new thing is that I build an analogy in terms of something I do understand. This can be dangerous when the analogy is wrong. I’m currently hanging on to the analogy that follows, so I’m publishing it as a straw man argument in the hope that those with more experience than me can critique it and help improve my understanding.

Proposition: Monads are what objects are supposed to look like

Throw away everything you know about Object-Oriented programming, particularly if you know Objective-C, Java, C++ or C#. Now go and read the first edition (the straightforward one, not the detective-novel second edition) of Object-Oriented Software Construction by Bertrand Meyer. You’ll find the principle of Command-Query Separation, that an object’s interface should provide distinct facilities for manipulating and investigating that object. Consider an object as an enclosed module analogous to an electronic circuit[*], with switches you can flip and lights you can observe. Watching a light shouldn’t also have the effect of flipping a switch, and you shouldn’t have to flip a switch in order to watch a light.

How could a language support that principle? Clearly imperative programming is too general, as it lets me mix commands and queries in the same place. What I need is an operation that lets me bind sequential commands together, taking an object in state a and a function that turns state a into state b and creating an object in state b. I also need an operation that lets me run a query, taking an object in state a and returning a value corresponding to a. Given those, and assuming the single responsibility principle has driven me to the point where my object does one thing and can be represented by a single command and query, then the interface on my object is complete.

Interestingly and usefully, except in the (common-ish) special case where my object needs to talk to the world, objects defined in this way are completely understandable mechanistically. The same sequence of commands applied to the same constructor will always yield the same value on query.

But that is, I think, what Monads are supposed to be: things that bind commands into sequences and allow inspection at points in the sequence. As stated in this post’s preamble, I’m not fully confident of this, and may be over-applying an analogy to replace a thing I don’t understand with the comfort of the thing I do. I’d be interested in hearing informed critique on the argument.

Not the other monads

When Alan Kay said that objects are monads, he was talking about Leibniz monads as previously discussed on this blog.

[*] An analogy already present in the proceedings of _that_ 1968 NATO conference, and drawn to extremes by Brad Cox in Object-Oriented Programming: An Evolutionary Approach.

Update

The discussion among my monadically-inclined friends on Facebook indicates that this analogy is incomplete. Yes, monads can be used like that, but they need not be used like that. Counter-examples included the reverse state monad in which state flows backwards, and the TARDIS monad in which state can flow in both directions.

Posted in FP, OOP | Leave a comment

Today I learned that I don’t even know how to Unix. I discovered that it’s possible for a POSIX system to leave PATH_MAX and similar variables undefined if it truly has no restrictions on their length.

Posted on by Graham | Leave a comment

About 10 years ago, we decided that the performance gains in single-core processors that come “for free” with advancing semiconductor processes were slowing down. Many chip makers switched to scaling the number of cores on a die, and promoted parallel programming for their products.

Today I learned that the free multicore lunch is over, too. You can no longer turn on all of the transistors in a single chip, so you can no longer get 2× the threads running by doubling the number of cores in your processor.

Posted on by Graham | 4 Comments

Like Java, only functional

An idea that clarified itself to me in discussion today is that Swift is to Functional Programming as Java is to Object-Oriented Programming: it is the thing that lets you write C and pretend you’ve adopted some posh-sounding “paradigmatic” non-imperative approach to programming.

I thought this was true shortly before lunch, but now climb partway down from the high horse. Swift is to Functional Programming as Java is to Object-Oriented Programming is still true. However Swift is to C# 3.0 as Java is to Objective-C.

Posted in code-level, Java | Leave a comment

Learning phases

I’ve been trying to learn things this week (specifically Haskell). So
far I’ve been through a lot of different moods, and I thought it’d be
handy to write them down so that next time I’m the teacher I can
remember what it’s like to be on the receiving end. I’m not sure I
(and certainly not anyone else) goes through all of these every
time, nor necessarily in the same order which I can’t remember anyway.

Frustration

These symbols all have no meaning to me, what is even going on here?

Atomic comprehension

If this symbol means that, and this symbol means that, then
combining these two must mean…

Holistic comprehension

OK, so this whole thing does this, which means that these parts must
somehow contribute to doing this. Let’s see…

Argument by analogy

Oh, hold on, what they’re saying is exactly like this other thing from
a different area of my experience. I’ll just pretend it’s the same for
the moment.

Paralysis of choice

I have a problem, and I’ve been given a bunch of tools, and I don’t
know which to apply.

All I have is a hammer

Well, I understood how to apply a lambda function to a collection with
map, so I’m going to contort this problem until it looks like I need
to apply a lambda function to a collection with map.

Progress by context

I have no idea what I’m supposed to do here, but I just read a section
on list comprehension so I bet I’m supposed to use [x | x <- xs]
somehow.

Confusion of dissimilarity

I have no idea how to turn that map into a comprehension or vice
versa, but I was able to produce each at different times on the same
day.

Joy of simplicity

You know what, it’s true when they say that if it type-checks, it
probably works.

Disillusion through broken dreams

Oh, off-by-one errors (and rotation of dimensions) still
type-check. This is bullshit.

Reinventing the wheel

So, I need a thing that applies this thing to all those things,
let me write a function applyFunction :: (a -> b) -> [a] -> [b] that
gives me one of those.

Discovering existing wheels

I have a thing and I need a different thing, let me look in the API
documentation until I find the function that does exactly that.

Rage-quitting

This error makes no sense, screw the entire city of Glasgow.

Rabbit hole tangents

This error makes no sense, but those words look sufficiently rare to
shove into Google. Ooh, three blog posts, a bug report and a PhD
thesis!

Trial and (type) error

This error makes no sense, but it’s telling me line 25 is wrong so
I’ll just rewrite line 25. Again. And again.

Stop! Hammock time

I have no idea how to solve this problem, but it’s
lunchtime. [Om nom nom] Ooh, this problem is trivial.

Minimum Viable Enlightenment

I don’t know what I got wrong, but based on the error message I think
I make this change…yes, that works. I don’t know what I got right.

Law of highfalutin words (I)

I wish someone could explain this to people who didn’t learn the word
“monoid” at school.

Law of highfalutin words (II)

Yes, I can help you with that problem, I just solved it myself. You
see, it becomes easier when you realise that these two things
constitute a monoid.

Posted in advancement of the self, edjercashun | 3 Comments

I’ve realised that when I read that a tool or framework is “opinionated”, I interpret that as meaning that I’m going to have to spend time on working out how to express my solution in its terms. I have enough trouble trying to work out how to express my solution in terms of my problem, so I’m probably going to avoid that tool or framework.

Posted on by Graham | 1 Comment

The Tankard Brigade

I have a guideline that seems to apply to many pursuits and hobbies: any activity can be fun until there’s too high a density of men with beards and tankards.

Of course, they aren’t all men (though many are) and don’t all have beards and tankards (though many do). But they can turn any enjoyable pastime into a maddeningly frustrating pursuit of ever-receding goals, like Zeno’s arrow approaching but never reaching its target.

Some background. For any activity there will be different levels of engagement; different extents to which once can take it seriously. For most people (apart from, in this simplified model, two people) there will be a collection of people who are less invested than they are, and a collection of people who take the pursuit more seriously.

Often, this doesn’t cause any disharmony. Some natural outgroup bias might make people believe that those who take it more seriously take themselves too seriously, and put too much effort into what should be an enjoyable way to spend one’s time. Similarly, those who take it less seriously are perhaps not really engaged with the activity, and can be a bit too frivolous. Of course the distance between my level of engagement and perception of the outgroup’s investment is decidedly non-linear: pro golfers and non-golfers do not cause as much difficulty for year-round and fair-weather amateurs as these two groups cause for each other.

This is all largely harmless snobbery and joshing until the men with beards and tankards come along. A man with a beard and a tankard (even if only figuratively a man with a figurative beard and tankard) is someone whose level of engagement with a pursuit must be the greatest of everyone in the room or online forum.

A single man with his solitary beard and tankard in a group can be harmless, endearing or slightly irritating. He will have bought the most expensive equipment available, and will gladly tell everyone who’ll listen (and many who would rahter not). He’ll explain why he got it, why it’s better, and why you simply can’t appreciate the subtleties and nuances of what you’re participating in (and apparently enjoying very well, thankyou very much) without the basic investment in a good…whatever that thing is they bought. Moreover, there’s only one way to engage in the activity, and that’s the way in which he does it. Anyone who has a different way, particularly one that invovles spending less time or money, is looked on in smiling condescenscion as one who simply doesn’t – and perhaps can’t – appreciate the craft in all its majestic glory. It might involve some eye-rolling, tutting, and perhaps a strategic choice of seat at the society Christmas dinner, but you can usually cope with one man with his beard and tankard.

Two or more, on the other hand, start to get out of hand (this one or the other one), because each wants to be at the apotheosis of his craft, neither can afford to be outdone by the other. The effect is of course an inescapable ratchet of dedication and investment, much like the ever-accelerating and ultimately ruinous cycle of gift-giving in potlatch societies. When one comes in with some new piece of kit, the other must have it or the one better than it. When one adopts some new and laborious way of interacting with the pursuit at hand, the other will immediately adopt or surpass it. Their interactions with each other are best described as ‘banter’, that particularly masculine (and indeed beard-ridden and betankarded) species of chatter that seems on the surface to be friendly ribaldry but that covers a seething and complex web of mistrust and hatred.

As I said earlier, I think that what really counts for enjoyment of a pursuit is the density of men with beards and tankards. Some activities seem able to hold at once both people with large individual investments, and a welcoming attitude toward newcomers and casual participants. Many runners and cyclists, regardless of how much they spent on their kit, will be happy with and friendly toward anyone who turns up to the same event to run or ride alongside them. The next person may be on their super-list carbon fibre frame with $5000 wheels and bespoje saddly uniquely contoured to fit their cheeks, when you turn up on the $250 bike you got in the January sales. But they’re a cyclist, and you’re a cyclist, so hey, let’s get some cycling going.

Some activities are clearly at the transition, where variations in the density of the tankard field can locally push it past the critical limit. Most motorcyclists are happy to acknowledge and welcome other bikers (though obviously not scooter riders), with a few notable exceptions. Harley riders tend to only notice other Harley riders. The extreme end of the amateur track circuit only pays attention to how much you’ve bored out your cylinders (and anyone who’ll listen) and the amount of time you spend riding a dynamometer. And that certain class of BMW rider who watched The Long Way Down can’t believe that you don’t have mud pans, GPS, and aluminium flight cases attached to your bike when you go to the corner shop for a pint of semi-skimmed. But still, most bikers accept most other bikers, and talk to them about most biking.

And then there are the activities that are forever lost to the men with beards and tankards, for which the ratchet has turned so far that even if the barrier to entry is theoretically low, the barrier to sociable entry – to engaging with the community as an equal – can be insurmountable.

Consider astronomy. It used to be that if you had some cheap army surplus binoculars, you could go along to your local astronomy society and discuss what you’d seen of the moon, the planets and some of the brighter objects in the Messier catalogue. Then, with the introduction of the charge-coupled detector, the tankard brigade arrived in force. Now people will swap photos constructed from multiple hundreds of exposures through different narrow-band filters, taken with their large reflecting telescopes with computer-controlled star drives and the latest in CCDs (all probably permanently housed in purpose-built observatories in their gardens). No multi-thousand-dollar telescope (perhaps even no garden)? Nothing to discuss.

In some circles, folk music can have a more practice-driven ratchet system. The British folk revival of the 1970s brought with it literal men with actual beards and genuine tankards who defined what folk singing was (in apparent contradiction to the idea that it should be up to the folk to decide). Now there exist folk clubs where unless you have that certain nasal folkier-than-thou timbre in your voice and practiced wobbly delivery, and unless you can remember all of the words to all twelve verses without recourse to the book, you probably shouldn’t take part.

All of this leads me to my questions. As a programmer, which of the practices I participate in are pragmatic, which necessary, and which informed by the ratchet of the men with beards and tankards? How much of what we do is determined by what others do, and must be seen to be done before we can claim we’re doing it right?

And which things? Is it the runaway complexity of type systems that’s the ratchet, or the insistence of programming without the safety net at all in a dynamic language? Or both?

My naive guess is that tankardism manifests where unnecessarily highfalutin words are deployed, like ‘paradigm’ for ‘style’ or ‘methodology’ for ‘method’. And yes, that sentence was deliberately unnecessarily highfalutin.

Posted in whatevs | Leave a comment