Friday, May 27, 2011

Keyword Functions in PHP

So, as spurned by a comment on hacker news relating to the lack of ability for keyword arguments in php I figured I would expound more upon the Phutility library, in particular the Func module.

Check it out:

#say you have a function (perhaps defined by you, perhaps not)

namespace SomeNamespace;
use Phutility\Func;

function testFunc($name, $eyes, $hair = 'blonde', $age = 0, $weight = 200, $goatFace = 'definitely') {
return array(
'name' => $name,
'eyes' => $eyes,
'hair' => $hair,
'age' => $age,
'weight' => $weight,
'goatFace' => $goatFace);
}

#if you want a keyword wrapper for it:

$testFuncWrapper = Func::keyword('\SomeNamespace\testFunc');

$result = $testFuncWrapper(
age, 30,
name, 'peter'
);

/*would yield a $result of
array(
'name' => 'peter',
'eyes' => 'blue',
'hair' => 'blonde',
'age' => 30,
'weight' => 1200,
'goatFace' => 'definitely'
)
*/

# If you want to not have a variable func you would need to do something like:
function TestFuncWrapper() {
static $wrapper;
if(!$wrapper) {
$wrapper = Func::keyword('\SomeNamespace\TestFunc');
}

return call_user_func_array($wrapper, func_get_args());
}

#a little gnarlier but this is the price we pay to call it like:

$result = TestFuncWrapper(
goatFace, 'NoWay'
);

#oops this would yield an exception because name and age are required!


If this is at all interesting to you and you'd like to use it or contribute, the source and tests are all up on github.

Wednesday, May 25, 2011

On unit testing

When ever I am confronted with a problem with a code base, my first reaction is: "wtfutfts" meaning "where's the fucking unit tests for that shit". No unit tests? Now you know your first move in providing resolution.

Alternative s-expression syntax for Soy Lisp

Soy is the name of my lisp dialect (previously called lisphp, and before that phlisp). This is quite a radical departure from standard lisp s-expression but not so far as to, say have infix notation or "sweet expressions". Rather this is a simple inverse of s-expression e.g.:

(if (predicate arg1 arg2)
(thenFunc arg2)
(elseFunc arg3))

Becomes:

if(predicate(arg1 arg2)
thenFunc(arg2)
elseFunc(arg3))

Your first question should be, "but wait! what about homoiconicity and the ability to have quasiquote macro definitions!?". I'm glad you asked, I have two proposals. 1) allow for a s-expression macro syntax, 2) allow for quasiquote to start with an atom:

defmacro(eat-apple person number-of-apples
`person-eat(,person 'apple ,number-of-apples))

You may have noticed the other drawback with this syntax is that it makes having macros which handle sublists a tad more difficult. As any atom followed by (, applies the atom to the arguments inside of the parens. This can be resolved by using rest args for forms which anticipate the last expression to be treated as a lambda. Also Soy allows for [ | ] lambda forms and { } vector/dicts. So it is also possible that would resolve any ambiguities.

One of my major ambitions with this is to have a very simple syntax for exploring alternative object models, similar to my previous post about an alternative object model for javascript.

;simple keyword selector
some-object(set-first-name: 'peter and-last-name: 'jenkum)
;chaining
some-object(some-keyword: arg1 selector: arg2)
(chained-selector: arg3 takes-closure: [ a | a(message: arg4)])
(another-chained-selector: [_(anon-var)])

I really dig how close this comes to snythesizing what I love about smalltalk w/ lisp w/o really forsaking either.

One of the real "wins" with this is when you have function returning functions .. n you don't end up w/ a massive amount of nesting.

(def adder [x | [y | [z | + x y z]]])
(((adder 6) 7) 8)

def(adder [x | [y | [z | +(x y z)]]])
adder(6)(7)(8)

I think the latter reads in a much more obvious "left to right" fashion.

Monday, May 23, 2011

simple keyword message selectors for javascript

As I have been messing with alternative object systems for php one of the ones I came up with was ab(using) the __invoke magic method to take a keyword argument list and find a given selector based upon it. I realized this could be done in an even more trivial manner in javascript using the object syntax and returning a new object w/ the dispatch mechanism rather than "return this".


var Klasses = {
'Person': {
'selectorPart1:selectorPart2': function(a, b) {
console.log('called with ' + a + ' and ' + b);
return obj(this);
},
'subSelector': function(a) {
console.log('subselector with:' + a + ' for ' + this.name);
return obj(this);
},
'get': function(field) {
console.log(this.name + ' over-ride of get with ' + field);
}
},
'*': {
'get': function(field) {
if(this[field]) {
return this[field]
} else {
throw new Exception('No field ' + field);
}
}
}
};

var obj = function(self) {
return function(selector) {
var sel = [];
var args = [];
$.each(selector, function(k, v) {
sel.push(k);
args.push(v);
});

var selectorName = sel.join(':');
var message = false;
if(Klasses[self.klass][selectorName]) {
message = Klasses[self.klass][selectorName];
}
else if(Klasses['*'][selectorName]) {
message = Klasses['*'][selectorName];
}

if(message) {
return message.apply(self, args);
}
};
}

var guy = obj({klass: 'Person', name: 'peter'});
guy({selectorPart1: 'apple', selectorPart2: 'candy'})
({subSelector: 'rotten'})

var otherGuy = obj({klass: 'Person', name: 'samuel'})({subSelector: 'cotton'})
console.log(otherGuy({get: 'name'}))


To see it live: jsfiddle running the above

Friday, May 20, 2011

On Phutility

Phutility is a collection of tools which I utilize in many of my other projects. For example the Node class is utilized by both covenants (sql builder) and also phmop (meta object protocol). Today though I am going to be discussing some of the work that I have been doing in Func to lay the framework for "higher order object oriented programming" with phmop. To give you an idea of what I am driving at, consider:

defineClass('Person',
slot('someMethod', function($self) {
$args = func_get_args();
$self = array_shift($args);
$options = appos($args);
if($self->{$options[ifField]} == $options[isValue]) {
$self->call($options[callMethod], $options[withValues]);
}
})->accessor('someMethod'));

$person = new Person;
$person->someMethod(
ifField, 'age',
isValue, 30,
callMethod, 'someMethod2',
withValues, array(300));

There are a few things we can cleanup. Firstly lets create a function "method" which wraps up simple functions which utilize an accessor which is the same as their internal name. Then lets utilize a higher order function "Func\options" which returns a function which has the last param defined as an options hash to clean things up:

defineClass('Person',
method('someMethod', Func\options(function($self, $options) {
if($self->{$options[ifField]} == $options[isValue]) {
$self->call($options[callMethod], $options[withValues]);}})));

But we can go further by creation an optionsMethod which wraps up the need for the explicit Func\options call. Also we can have it pass a param which gives us back a std class for options rather than an array.

defineClass('Person',
optionsMethod('someMethod', function($self, $options) {
if($self->{$options->ifField} == $options->isValue) {
$self->call($options->callMethod, $options->withValues);}}));

For the sake of completeness let me show off another way this could be defined more explicitly taking advantage of Func\keyword which evaluates a closure and then returns a function which responds to an appositive style call:

$keywordFunc = Func\keyword(function($age, $name, $color) {
return array('age' => $age, 'name' => $name, 'color' => $color);
});

print_r($keywordFunc(
age, 30,
color, 'blue',
name, 'peter'));

array(
'age' => 30,
'name' => 'peter',
'color' => 'blue');

As you can see this allows us to pass the params in any order we please (which to be fair our Func\options implementation does as well but packaged into an $options var). So now we will skip to step 3 of what a keywordMethod would look like in use:

defineClass('Person',
keywordMethod('someMethod',
function($self, $ifField, $isValue, $callMethod, $withValues) {
if($self->$ifField == $isValue) {
$self->call($callMethod, $withValues);}}));

$person = new Person;
$person->someMethod(
ifField, 'age',
isValue, 30,
callMethod, 'someMethod2',
withValues, array(300));

I think this makes clear why both a meta object protocol and higher order functions are so awesome when they can play together. Rather than having only inheritence, interfaces, or even mixins, as the tool for making things more elegant we can easily add new features to our language with simple function composition.

Wednesday, May 18, 2011

Considering a MetaObject Protocol for PHP

The purpose of a "MetaObject Protocol" is to allow for defining the very nature of how an object system functions. This means the ability to add traits/mixins, aspects, multiple inheritance, "Generics" etc. w/o requiring compilation or low level tinkering. One major advantage is that this means not having to wait for a revision of your language to express certain design patterns.

As usual php is so close, yet so far away. However ab/utiliz/ing the magic methods you can actually get pretty close to something resembling the CLOS system. To accomplish this it requires a few building blocks which I have abstracted into my Phutility library. Primarily the MetaArg and Node which provide the building blocks for composing declarative domain specific languages.

The majority of the magic occurs via macro expansion in CLOS. We are going to make up for that via declaring an abstract syntax tree (AST) which we will expand and weave into our method dispatch mechanism.

Enough talk, let's code. First our goal is be able to declare classes and methods.


defineClass('Shape',
slot('width'),
slot('height'),
method('getHeight', function($self) {
return $self->height;
}),
method('getArea', function($self) {
return $self->width * $self->height;
})
);

$shape = new Shape(
width, 20,
height, 50
);

echo $shape->getHeight();
echo $shape->getArea();

defineGeneric('beforeGetArea',
before(getArea),
arity(Shape),
function($self) {
echo "Called before get area!\n";
}
);

echo $shape->getArea(); //outputs "Called before get area!" and then area


Looks like a class and acts like a class. But most definitely not a raw class. How does this work? Principally we keep the meta information about each class in a Registry. Each class defined results in a simple declaration of "class X extends \phmop\StandardClass{}" which allows the usual "new Class" syntax. It writes this to a cache directory and does a require_once on it so as to avoid eval.

The base Obj class looks something like:

class StandardClass {
public $slots = array();

public function __call($slot, $args) {
return Registry::dispatchMethod($this, $slot, $args);
}

public function &__get($slot) {
return Registry::getSlot($this, $slot);
}

public function __set($slot, $value) {
Registry::setSlot($this, $slot, $value);
}

public function __construct() {
foreach(Appos(func_get_args()) as $key => $val) {
$this->$key = $val;
}
}
}


So pretty clearly the real magic is taking place in the way that defineClass, defineGeneric, and friends interoperate with the Registry.

I am going to end things here for now as I need to make a few posts about some of the inner workings of phutility to really get into the thick of things.