Code::Splice -- people keeping asking why. Here's why.

scrottie on 2007-05-27T22:46:24

I keep writing modules, and of course talking about them, when I get the chance. No one ever says, "oh, that's useful", or "I'm glad Perl has that now even though I'll probably never need it" -- they just ask why. That happened when I did typesafety.pm. No one seemed to think it was neat that you could write strongly typed Perl if you so desired. No one could imagine that one piece of code in the project could need its interface changed along with the code that depenended on it and that they'd want to be warned if they missed updating a piece of code. It's just not the Perl way; the Perl way is to avoid refactoring because you might break something, and lack coverage for it in automated or manual testing, or to rely on testing and hoping for perfect coverage. The short version is, there are damn good reasons for type checking that sometimes come up. I've repeated this argument over and over again. People keep making feebile arguments and then just refuse to think about it any more.

So when I wrote Code::Splice, I wasn't surprised that not only could no one think of a use for it, but they were dubious about any existing at all. What the hell has happened to us? Is unit testing and MVC the end all and be all -- have we "arrived" and there is now no future? Sure, code splicing probably isn't the future, but the curiousity is gone from the Perl camp. Or the naturally curious have defected to other places that are at least excited about their own technology and their goals. Ruby's culture seems to be very good at covering lots of technical turf, but doing it in an elegant, minimalish way that keeps things from crumbling under the weight of their own complexity.

Okay, bitches. Here's why Code::Splice. To inline method definitions in cases where there are no subclasses of a class and this optimization can safely be done. To search-and-replace dangerous code constructs, to upgrade them, such as replacing blocking reads with Coro-friendly calls that give up the CPU to runable contexts. To write tests for extremely hard-to-test code without mocking half of the known universe including the DBI -- this was the original reason.

Questions of why code splice came up during the Google interview. The interviewer commented that "that's the only good reason I've heard", in the context of optimizing OO programs with code splicing. I didn't have the heart to mention testing for fear of seeming like a code splicing zealot.

I'm applying mad science to testing -- replacing probably incomplete and manual unit tests with static analysis, and devising schemes for testing the bulk of the existing code out there, which is horrific. But the knee jerk reactions of "we're going to do this right" -- even though the application is hundreds of thousands of lines of speghetti, fragile, time consuming to learn and debug -- still keep companies from turning to mad science. There are no comprimises; no optimizations. Legacy code is a hard problem; I've tried to raise to to the challenge (and succeded in doing so when people didn't stand in my way). The Perl community has left their imagination behind on dealing with this problem just as they're trying to leave their quick and dirty style behind. Is there now no room for cleverness? Do we do everything only according to prescribed methodologies that are endorced by well read evangalists? Do we dodge blame for any failure by punting all decisions to software engineering group-think? Are we like Detroit, having failed to keep up with the desires of the market, now entirely mechanical about building soulless mechanisms using only formulas and specifications? Have we become just Python or Java programmers but without giving up Perl's syntax?

If I stop and think about it, I can come up with a lot more ideas for Code::Splice. A proper implementation of the CoreWars game, where your virus-like program attempts to take over all of core in a simulated computer and wike out your opponets, is now possible in Perl. Can you think of any? Do you care to? Or is anything not directly related to MVC or RSS just pointless?

There are infinite possibilities -- love them. The best ideas haven't even been thought of yet. Don't become a slave to the few things that are currently in fashion.

-scott


Oh wow that looks cool

Alias on 2007-05-28T01:50:39

> To write tests for extremely hard-to-test code without mocking half of the known universe including the DBI -- this was the original reason.

Holy crap, why didn't I know this exists.

This is way way cool.

I have some really evil testing cases that I've been to write for ages, but lacked a way to sanely inject stuff into the guts of code.

Some questions though...

The version dependency is current 5.008, is there any way it can go back to 5.005, or is it's use of internals just going to make 5.008 something that can't be changed?

Can you write a little more documentation in the POD on how to use it?

I understand WHAT it does, but I don't quite get how the use of the precondition stuff works to control the inject point.

A couple of examples of the "here's the code before, here's the splice call, here's the equivalent Perl for what the code will be like after" variety would be helpful.

And finally, since this uses internals, how stable do you forsee the code being over the long term? (i.e. the remaining 5-10 year lifespan of Perl 5).

Re:Oh wow that looks cool

scrottie on 2007-06-06T03:04:33


Hey Alias,

Re: 5.005, it *might* work, but I'm afraid to find out.

As for examples, read through the t/* directory. They print stuff out on each line, so the output of the program reflects the post-modification state. If you can sort it out from reading and playing with those, send me some doc patches.

I'd take your interest as plenty of motivation to go do some more (doubtlessly needed) work on the documentation, but I'm in middle of something else I need to hurry up and get done so I can go get some other stuff done that's overdue.

Briefly, the algorithm for finding where to do the splice is to walk through the function in question until all of the pre-conditions have been met (they all matched somewhere). At that point, if any of the post-conditions have also matched, an error is thrown. The post-conditions are nothing more than sanity tests to make sure that the target code hasn't changed too much for the splice to be safe to apply.

It depends on B::Generate and B::Deparse and bits of B::Deparse's internal API. It also depends on a formula for re-threading the bytecode that's probably just wishful thinking. The whole thing is highly experimental. For continued viability, that depends mostly on its dependencies, which I can't really make any guess about, other than I haven't heard discussion of axing either of those two modules.

One last thing -- if you do get some tests written for hairy old code, get in touch. Perhaps we can collaborate on an article or something >=) That's assuming some time will open up...

-scott

Fantastic!

chromatic on 2007-05-28T06:59:00

I didn't see this when you uploaded it. You've saved me having to write it myself. Thank you!

But... does it work?

bart on 2007-05-28T10:55:04

You said

To search-and-replace dangerous code constructs, to upgrade them, such as replacing blocking reads with Coro-friendly calls that give up the CPU to runable contexts.
That sounds really neat. But... can you prove it works? Or can you prove that (and when) it fails? Warn us when it just isn't sure?

Everybody in the Perl world that Perl is extremely difficult to parse. That's the reason why you shouldn't use Switch in production. Because, it might work most of the time, but there is no warning if it fails.

So, if this system could just garantee to us that what it produced works identically to the original code, when it indeed is the case, or warn us when it found a construct that is known to be flakey, that might inspire us to have more trust in systems like these. But now, many of us think it's just too risky to do anything more with it, than just play with it. And the professionals you're targetting, just don't feel like they can justify to take the time to play.

Re:But... does it work?

scrottie on 2007-06-06T03:12:54


I'm not sure we're talking about the same thing. B::Splice does not parse Perl, and it doesn't use PPI to try to parse Perl. It uses B::Generate. Go read the perldoc then comment again if anything you meant to say still applies.

As far as targeting professionals, I don't remember saying anything about that either. In fact, my post taunted the Perl community for acting too much like professionals and not enough like mad scientists. Er, pardon me... it seems as though you're having a conversation with yourself. That it appeared in a comment on my blog threw me for a minute there. Nevermind.

-scott

Code::Splice

chorny on 2007-05-28T11:39:37

You use B::Generate for Code::Splice and typesafety, but even dev version, 1.06_2, has serious problems.
Code::Splice itself has cpantesters results "PASS (1) FAIL (6) NA (1)".

I already see some cases to use Code::Splice for testing.

Re:Code::Splice

scrottie on 2007-06-06T03:09:29


The documentation clearly states that it requires my own version of B::Generate, that's posted in my author area on CPAN. I should probably just fork B::Generate and maintain a copy full on (I want to add support for creating lexicals on the fly, especially since a lot of ops need temps on the pad)... anyway, that's something I can't worry about right now, but would reconsider if people actually did start using the sucker.

Thanks for your comment. Feel free to email me questions or examples of things you've used it for.

Cheers,
-scott