[13574 total ]
Andy Wingo: optionals, keywords, oh my!

OK! Where were we?

In my last dispatch, I talked about case-lambda in guile. The gist of it is, let procedures parse their own arguments, and they can do neat stuff like multiple-arity dispatch.

Also, neat stuff like optional and ... [More] keyword arguments! Consider our my-write example from last time:

(define my-write
(case-lambda
((obj port) (write obj port))
((obj) (my-write obj (current-output-port)))))
It's a little silly, to write it this way. It's not essentially one procedure with two different bodies, it's one procedure with one required argument, and one optional argument. The optional argument defaults to (current-output-port).

So, as you would imagine, there is a better way to express this "design pattern": lambda*, and its sugary friend, define*.

In this case, we would simply define my-write like so:

(define* (my-write obj #:optional (port (current-output-port)))
(write obj port))
So nice, so clear. Default values are only evaluated if the argument is missing. (It's a rare Python programmer that's not surprised about Python's behavior in this regard; but I digress.)

keyword args too

Optional arguments are good at allowing for concision and extensibility, but code that uses them can be confusing to read. Actually this is a problem with positionally-bound arguments in general.

I like how Carl Worth puts it: that nice prototypes can result in inscrutable code. His solution in C is to have function names encode their arities, but we can do better in Scheme, with keyword arguments.

So let's say we want to add a "detailed" argument to my-write. We can add a keyword argument:

(define* (my-write obj
#:optional (port (current-output-port))
#:key (detailed? #f))
(if detailed?
(format port "Object ~s of type ~s" obj (class-of obj))
(write obj port)))
Invocations are really nice to read:

(my-write 'foo #:detailed? #t)
=| Object foo of type #<<class> <symbol> 8c4fca8>

(my-write 'foo (open-output-file "foo.log") #:detailed? #t)
; writes the same thing to foo.log
The second example gives an explicit port; and indeed, I am left wondering what it is, when I read it. Keyword arguments make for more readable code.

Keyword arguments also allow for better extensibility. But don't take it from me, take it from P. Griddy:

Most of the operators in Rtml were designed to take keyword parameters, and what a help that turned out to be. If I wanted to add another dimension to the behavior of one of the operators, I could just add a new keyword parameter, and everyone’s existing templates would continue to work. A few of the Rtml operators didn’t take keyword parameters, because I didn’t think I’d ever need to change them, and almost every one I ended up kicking myself about later. If I could go back and start over from scratch, one of the things I’d change would be that I’d make every Rtml operator take keyword parameters.

-- Paul Graham, from a talk he gave back when he didn't talk about startups so durn much

And, there's one more thing, which applies both to optional and keyword arguments: the default values are evaluated in the lexical context of their preceding arguments. So you can have a later argument referring to an earlier one. For example, Guile's compile is defined like this:

(define* (compile x #:key
(from (current-language))
(to 'value)
(env (default-environment from))
(opts '()))
;; wizardly things here
...)
See how env's default value references from? Awesome, yes? I thought so.

newness

So what's new about all this? Not much, semantically. Guile has supported lambda* and define* for more than 10 years. But now they are available in the default environment, and they are fast fast fast -- for the same reasons that case-lambda is faster now. There are special opcodes to process stack arguments into optionals, and to shuffle and bind keyword arguments, all without consing a single cell.

Also, now the toolchain knows about optional and keyword arguments, so that backtraces and printouts show them nicely. For example, my-write prints like this:

#<program my-write (obj #:optional port #:key detailed?)>
Ah, there is case-lambda*; though it is of dubious utility, given that it can only reasonably dispatch on the required and optional arity, and not on keyword args. But there it is.

In any case, I look forward to using lambda* more in the future, without speed trepidations. Just say no to rest arguments masquerading as optionals! [Less]

Henri Bergius: Will we learn to hide the complexity in Open Source?

Chris Messina has a pretty good story comparing Apple's Magic Mouse and the recently announced OpenOfficeMouse that was targeted to power users of OpenOffice.org:

At base, these products represent two polar opposite ends of the spectrum: ... [More] Apple prefers to hide complexity within the technology whereas the open source approach puts the complexity on the surface of the device in order to expose advanced functionality and greater transparency into how to directly manipulate the device. Put another way, the reason that people would buy the $69 Apple MagicMouse is because they want Apple’s designers to just “figure it out” for them, and provide them with an instantly-usable product. The reason why someone would pay $75 for this mouse is because it strictly keeps all the decision-making about what the mouse does in the hands (pun intended?) of the purchaser.

What I worry about, however, is that pockets of the open source community continue to largely be defined and driven by complexity, exclusivity, technocracy, and machismo. While I do support independence and freedom of choice in technology — and therefore open source — I prefer to do so inclusively, with an understanding that there are many more people who are not yet well served by technology because appropriate technology has not been made more usable for them.
More focus on usability and clarity would be needed with most Open Source projects, but there are already some bright spots. GNOME, for example, has good tradition in simple interfaces. I recently made the jump from Mac OS X to Ubuntu Netbook Remix, and have generally been quite happy with it.

But for Open Source projects the challenge is more difficult than for proprietary products. On the other hand we want to provide a nice, usable experience, but we also want to let our users delve deeper into the functionality, to make changes and maybe even become contributors to the project. This is where new tools like OLPC's View Source button can do wonders if implemented more widely. [Less]

Máirín Duffy: Fedora 12 rocks on tablets



(That’s Fedora 12 Beta’s Inkscape on my Thinkpad x61 with a built-in Wacom digitizer in the photo. Photo credit David Aquilina, CC-BY-3.0)

Got a tablet, or want to get one, but not sure it’s going to work out in Linux? ... [More] Here’s how my Thinkpad x61’s built-in Wacom tablet works in Fedora 12 Beta:

Tablet pressure sensitivity out-of-the-box, no xorg.conf needed! (Well okay, so that’s been the case for a couple Fedora releases now )
Cellwriter provides handwriting recognition text input (no more having to flip the tablet back to keyboard mode just for one stupid little thing.)
Xournal is great for taking notes & signing documents. No more print, sign, and re-scan; I can just sign emailed digital documents on screen and email them right back.
Gimp brush dynamics effects rock – they’re the secret to achieve quite a few of the effects in the Fedora 12 wallpaper designs.
The new Inkscape in Fedora 12 has a cool new feature that allows you to create your own brushes and save them or choose from a collection of preset brushes.

Fedora is truly committed to software freedom. Enjoy great features like this without the guilt. Try Fedora 12 Beta today. Or wait until Fedora 12 final comes out:

Posted in Uncategorized [Less]

Danielle Madeley: decorator factory for dbus-python methods

This is a crazy idea I had; that I want to share with people.

When you're implementing an object in dbus-python, you decorate your published method calls like this:
class ExampleObserver(dbus.service.Object):
...

... [More] @dbus.service.method(dbus_interface=telepathy.interfaces.CLIENT_OBSERVER,
in_signature='ooa(oa{sv})oaoa{sv}',
out_signature='')
def ObserveChannels(self, account, connection, channels, dispatch_operation,
requests_satisfied, observer_info):
...The input and output signatures are incredibly easy to get wrong. The thing is, most D-Bus APIs (e.g. Telepathy) have a specification that contains these arguments. Some APIs (e.g. Telepathy-Python) provide generated code including interface names and constants. So why can't we do something more like?
class ExampleObserver(dbus.service.Object):
...

@telepathy.decorators.Telepathy.Client.Observer.ObserveChannels
def ObserveChannels(self, account, connection, channels, dispatch_operation,
requests_satisfied, observer_info):
...With a decorator factory that looks up the parameters and then wraps the dbus.service.method factory.

Well, I just wrote a proof-of-concept. It looks something like this:
class Decorators(object):
methods = {
'org.freedesktop.DBus.Properties.GetAll': [ 's', 'a{sv}' ],
'org.freedesktop.DBus.Properties.Get': [ 'ss', 'v' ],
'org.freedesktop.Telepathy.Client.Observer.ObserveChannels': [ 'ooa(oa{sv})oaoa{sv}', '' ],
}

def __init__(self, namespace):
self._namespace = namespace

def __getattr__(self, key):
return Decorators('%s.%s' % (self._namespace, key))

def __call__(self, func):
iface = self._namespace.rsplit('.', 1)[0]
in_sig, out_sig = self.methods[self._namespace]
return dbus.service.method(dbus_interface=iface,
in_signature=in_sig,
out_signature=out_sig)(func)

def __str__(self):
return self._namespace

decorators = Decorators('org.freedesktop')Obviously in the real version, it would have a generated map of functions, or map of interfaces each with a map of functions, and a way to handle signals, but neat huh? [Less]

Johnny Jacob: ACL Reconstruction recovery journal

Tore my ACL while playing badminton. An awesome jump, delivered a smash at a impressive angle. On landing I slipped twisting my ankle and entire weight of my body fell on the right knee. After 15 minutes I was walking out of the club with the ... [More] idea of a 10k ride (cycle) back home. Probably I was high on adrenaline/endorphins. But as soon as walked 20 meters, I couldn’t take another step.

Friends helped me out. Few days later a MRI confirmed the ACL tear. Sought opinions from 3 surgeons. A day later I was scheduled for ACL Reconstruction.

Day 0 : Wheeled into surgery. Got shots of anaesthesia in my spine. 5 minutes into the procedure I started feeling my knee again. Then some new shots to my neck and i’m out for next 4 hours. Woke up in recovery room. Crying with pain in my thigh and knee.

Day 1 : High fever. Unable to move my leg. Felt like a dead log.

Day 2 : Realised that morphine (a better refined form .. Fentanyl ?) is being pumped in to me 24 hours.

Day 3: Fever continues. Unable to therapy. But was on CPM.

Day 5 : First time moved around 10 meters (felt like 5 km) to physio rehab. Was able to walk holding support ramps. Did some weight excercises. Morale boost.

Day 6 : Fever started fading.

Day 7 : Discharged from hospital. Realized I lost so much muscle mass. Right leg is very lean.

Day 8 : Woke up at brother’s place. Good food. Ate like a hungry pig.

Day 11 : Regained some strength in the thighs. Able to move around confidently with support.

Day 16 : Moved back to my own place.

Day 17 : Afraid to bend my knee. Looks like I’m resisting to bend the knee.

Day 18 : Able to sit with around 90 degree bend in my knee. Noticed some muscle development.

Day 19 : 90 Degrees knee bending

Day 21 : Mental battle is tougher than actually bending the knee.

Day 22 : Walking without support (crutches). Yay!

Able to handle stairs without support.

Day 25 : 95 – 100 Degrees. Moving to Squat exercises.

Started riding on a stationary bike. Able to walk  small distance with little limp.

Day 31 : 115 Degrees. Knee feels stronger.

Day NN : Recovery still continuing. Yet to build muscles. And regain those remaining degrees. But I’m confident now that i would be back to 110% in few months (yeah .. months!).

I should confess that I’m not a very fit athlete. I’m just a ordinary clumsy guy who started playing a bit. So this is my recovery timeline. Rehab is the tough part. Painful and needs a good amount of will power to keep doing it. It is going to take a long time to get back to my running (hopefully a marathon!). Can’t wait to get back on my bike (cycle).

One thing I kept remembering was this “Pain is temporary. Quitting lasts forever” (Lance Armstrong). In this case it is literally true.

Notes :

Do research. Learn about the injury and the procedure before you go in. Helps a lot. Realize that you have options on the graft being used.
Ice is the best pain management you got. I personally don’t like pain killers.
Most of the online materials on this subject give times lines for fit athletes. So don’t get discouraged if you are not. Keep at it.
Mail from nice people at Bangalore Bikers Club

Misc :

Fun when you are on a stretcher and pushed around. Profound
Scary part was not the surgery, but the catheter in my arm. Got over it after a day.
Enjoyed the royal treatment. People always around you. don’t have to do anything. Everything is there as soon as you think about it!
I was without a laptop for about 15 days.
Long phone calls from stoned friends.

(Would try to add more information and keep this post updated ..)
[Less]

Paul Cutler: GNOME Marketing Hackfest & Chicago GNOME Meetup

We are just days away from the Marketing Hackfest in Chicago, IL. Thanks to Novell and Google’s sponsorship, nine of us are converging in Google’s Chicago office for two days.

While we’re there, we’d like to invite any Chicago ... [More] GNOME users and developers to join us for a drink or bite to eat Tuesday night at 6:30 p.m. at the Rock Bottom Brewery at One West Grand Ave.

I look forward to seeing you there! [Less]

Mikkel Kamstrup Erlandsen: All My Bags Are Packed, I’m Ready to Go

I’ve prepped up for the upcoming Zeitgeist hackfest in Bolzano, bags packed, laptop charged, and kissed the kids goodnight and extra time. I have to get up at 3.40 this night in order to catch my plane.

It’s going to be great to catch up ... [More] with the other developers and finally meet them face to face. It’s always an odd feeling meeting people in real life for the first time when you talked so much with them on various online mediums.

My personal aim for the hackfest is to do a lot of coding and really push Zeitgeist closer to production readiness. We done a lot of drafting and discussion lately, so we are really set to get the actual coding done now. I have a lot of travelling time before I get there so I expect to get a head start on the hacking

Huge props to the sponsors and organizers! [Less]

Nicolas Trangez: Facebook goes XMPP?

MacBook:~ nicolas $ telnet chat.facebook.com 5222
Trying 69.63.176.191...
Connected to chat.facebook.com.
Escape character is '^]'.
<stream />
<?xml version="1.0"?><stream:stream id="F6DE2CB5" ... [More] from="chat.facebook.com" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" xml:lang="en"><stream:error><invalid-namespace xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error></stream:stream>

Connection closed by foreign host.

Jay! [Less]

Natan Yellin: Zeitgeist Hackfest

In 12 hours I’m going to board a plane at Ben Gurion Intl Airport for Munich. 8 hours later I’ll take a train to Italy and only 3 hours after that I’ll arrive in Bolzano, Italy for the Zeitgeist Hackfest.

Many thanks go to the GNOME ... [More] Foundation and Canonical for sponsoring the hackfest and to the South Tyrol Free Software Center for organizing and hosting it.

I’ll see you in Bolzano! [Less]

Andy Wingo: case-lambda in guile

Oh man, does the hack proceed apace. I really haven't had time to write about it all, but stories don't tell themselves, so it's back behind the megaphone for me.

Guile is doing well, with the monthly release train still on the roll. Check ... [More] the latest news entries for the particulars of the past; but here I'd like to write about a couple aspects of the present.

First, case-lambda. The dilly here is that sometimes you want a procedure that can take N or M arguments. For example, Scheme's write can be invoked as:

(write "Hi." (current-output-port))
=| "Hi."
(=| means "prints", in the same way that => means "yields".)

But actually you can omit the second argument, because it defaults to the current output port anyway, and just do:

(write "Hi.")
=| "Hi."
Well hello. So the question: how can one procedure take two different numbers of arguments -- how can it have two different arities?

The standard answer in Scheme is the "rest argument", as in "this procedure has two arguments, and put the rest in the third." The syntax for it is not very elegant, because it introduces improper lists into the code:

(define (foo a b . c)
(format #t "~a ~a ~a\n" a b c))
(foo 1 2 3 4)
=| 1 2 (3 4)
You see that 1 and 2 are apart, but that 3 and 4 have been consed into a list. Rest args are great when your procedure really does take any number of arguments, but if the true situation is that your procedure simply takes 1 or 2 arguments, you end up with code like this:

(define my-write
(lambda (obj . rest)
(let ((port (if (pair? rest)
(car rest)
(current-output-port))))
(write obj port))))
It's ugly, and it's not expressive. What's more, there's a bug in the code above -- that you can give it 3 arguments and it does not complain. And even more than that, it actually has to allocate memory to store the rest argument, on every function call. (Whole-program analysis can recover this, but that is an entirely different kettle of fish.)

The solution to this is case-lambda, which allows you to have one procedure with many different arities.

(define my-write
(case-lambda
((obj port) (write obj port))
((obj) (my-write obj (current-output-port)))))
implementation

You can implement case-lambda in terms of rest arguments, with macros. Guile did so for many years. But you don't get the efficiency benefits that way, and all of your tools still assume functions only have one arity.

Probably the first time you make a VM, you encode the arity of a procedure into the procedure itself, in some kind of header. Then the opcodes that do calls or tail-calls or what-have-you check the procedure header against the number of arguments, to make sure that everything is right before transferring control to the new procedure.

Well with case-lambda that's not a good idea. Actually if you think a bit, there are all kinds of things that procedures might want to do with their arguments -- optional and keyword arguments, for example. (I'll discuss those shortly.) Or when you are implementing Elisp, and you have a rest argument, you should make a nil-terminated list instead of a null-terminated list. Et cetera. Many variations, and yet the base case should be fast.

The answer is to make calling a procedure very simple -- just a jump to the new location. Then let the procedure that's being called handle its arguments. If it's a simple procedure, then it's a simple check, or if it's a case-lambda, then you have some dispatch. Indeed in Guile's VM now there are opcodes to branch based on the number of arguments.

So much for the VM; what about the compiler and the toolchain? For the compiler it's got its ups and downs. Instead of a <lambda> that just has its arguments and body, it now has no arguments, and a <lambda-case> as its body. Each lambda-case has an "alternate", the next one in the series. More complicated.

Then you have the debugging information about the arities. The deal here is that there are parts of a procedure that have arities, probably contiguous parts, and there are parts that have no arity at all. For example, program counter 0 in most procedures has no arity -- no bindings have been made from the arguments to local variables -- because the number of arguments hasn't been checked yet. And if that check fails, you'll want to show those arguments on your stacktrace. Complication there too.

And the introspection procedures, like procedure-arguments and such, all need to be updated. On the plus side, and this is a big plus, now there is much more debugging information available. Argument names for the different case-lambda clauses, and whether they are required or rest arguments -- and also optional and keyword arguments. This is nice. So for example my-write prints like this:

#<program my-write (obj port) | (obj)>
So yeah, Guile does efficient multiple-arity dispatch now, and has the toolchain to back it up.

Next up, efficient optional and keyword arguments. Tata for now! [Less]