Chad Perrin: SOB

26 May 2006

Lexical Closures as Object Model

Filed under: Geek — apotheon @ 02:53

Do I have any expert Perl hackers in the audience today?

I've been rereading some of what Jonathan Rees has to say about the object oriented programming menu. I've only read this stuff about a half-dozen times before, and I've been reading about the Perl object model recently, so I decided to get another look at what JAR has to say about the definition of OOP.

In reading about the Perl object model, I was disappointed. My excited utterance, as I learn new things about it, is this:

Ho hum.

This is in stark contrast to my response when reading about lexical closures in Perl. Perl closures made me jump up and shout "Eureka!" (or do something a touch more dignified and me-ish, while mentally I was cavorting and shouting Greek words). With much consideration of what the Perl object model attempts to accomplish, how it relates to other languages' object models, what I know of how CLOS was put together for doing OOP in Lisp (apparently a lot of reliance on lexcial closures is involved), and what JAR has to say about the malleable definition of OOP, I've come to some interesting continuations (since "conclusions" is kinda final, and I'm still in the middle) about the potential for OOP in Perl.

I have a notion that, though the object model would be fairly foreign to people coming to Perl from C++ or Java, Perl has an unofficial object model in place sorta "behind" or alongside its official object model, and it's pretty much entirely made up of leverage applied to its lexical closures. Making use of Perl closures for object-oriented programming while entirely ignoring bless() seems to provide a pretty significant chunk of the a la carte OOP menu JAR proposes. It appears to satisfy the needs of the following points:

  • encapsulation — syntactically hide implementations of objects
  • protection — maintain a consistent API for objects by keeping client code ignorant of its implementation
  • AYCDISAM — All You Can Do (to an object) Is Send (it) A Message
  • inheritance — I'm a little sketchy on what JAR means by the two different types of inheritance he mentions, but it seems that "object oriented" inheritance is definitely possible with Perl lexical closures.

I could be wrong about a couple of those, but then some of the others could also apply. I'm not really sure. I ask for expert Perl hackers because I'd like to know where I'm wrong.

What is clearly right, however, is the fact that at least some form of object model exists in Perl via lexical closures even without bless() in the allowed toolkit. Something else that is clear, at least from where I'm sitting right now, is that this object model is much cleaner to use than the official Perl OOP tools that come to mind when someone talks about doing OOP with Perl. It's entirely possible that some things one might wish to do with OOP might not be possible, or at least reasonably easy, without the official object model, but so far I don't really see it. I think the major problem is simply that a Perl closure object model would be so alien to most Perl hackers (coming from a VB, PHP, C++, and Java backround for OOP, or even from Python, most likely) that they'd have to reorient their brains to adjust to the very different approach to OOP that lexical closures provide.

Seriously, folks, I'm sure I'm missing something. Please explain.

11 Comments

  1. Well, I'm no Perl expert, but I have done some hacking. I see your point about closures being a light-weight form of OOP. This O'Reilly article presents an easy explanation of closures for the uninitiated. In it, I found this:

    It's because of this property that Barrie Slaymaker calls closures "inside-out objects:" objects are data that have some subroutines attached to them, and closures are subroutines that have some data attached to them.

    So yes, because of the scoping of closures, you get a lot of the features of an object. I'm not sure how inheritance fits into that, though. Perhaps you could give us an example?

    Comment by SterlingCamden — 26 May 2006 @ 11:49

  2. Without giving you working code (too much effort for my brane right now), I'll just say this:

    Closures could be created that make use of other closures. In addition, a single subroutine could be used to conditionally generate a set of separate closures, each when needed based on what you feed the subroutine — turning the larger subroutine into a sort of parent class with stuff inherited by the closures that are spun off from it. It all adds up to a kind of bass-ackwards inheritance scheme, but it achieves similar benefits for the programmer.

    Considering that the anonymous subroutine that becomes the lexical closure when its parent goes out of scope needn't be simple (it just usually is), there's all kinds of interesting object oriented stuff that can be achieved within closures and by interactions between them. Of course, the manner in which it's achieved would necessarily be quite different than Java and C++ programmers would be used to seeing and require some adjustment.

    I might be underestimating the difficulty of the whole exercise, of course, having never really worked with lexical closures all that much.

    I'm suddenly even imagining anonymous blocks within a closure that might go out of scope while the closure itself doesn't. I haven't considered this in any detail yet, so I'm not sure Perl closures support it, but that'd be an interesting way to handle closure creation and inheritance. Hmm.

    Comment by apotheon — 26 May 2006 @ 12:34

  3. Kind of depends what you mean. People talk about closures as objects but I've never known anyone to make real use of them. Tom Christenson gave a quick-n-dirty intro to closures as an OO implementation in perltoot (http://search.cpan.org/dist/perl/pod/perltoot.pod#ClosuresasObjects). But that really only describes what in Java would be a "bean," little more than a hash with a predetermined set of keys. In fact, as implemented you can just call the closure directly for arbitrary access, so it is just a hash with a pointless closure intermediary. Making something more interesting of it is left as an exercise.

    The whole point of implementing an object as a closure in Perl is that it can offer real encapsulation and protection of the object's data elements because only the closure can access them. But in order to actually achieve that, some hijinks are necesary. If the closure is little more than a transparent wrapper, you don't have real protection, because you can't really stop anyone from calling the closure directly to get at stuff (Tom's suggestion about restricting access to class methods notwithstanding — trivial to subvert in Perl). So it seems clear to me that real protection could only be accomplished by having much or all of the logic for the class implemented as part of the closure itself. But this would play havoc with inheritance. There's no way for a subclass to add members and logic to its superclass's lexical space; the only way to subclass such a thing would be to wrap it and override (or autoload) all of its methods with SUPER implementations that dispatch to the wrapped object — possible, but unwieldy (which I think describes closures-as-OO in general). You could implement inheritance relatively easily with thinly-wrapped-hash closures, but then you don't really have protection. To me, it seems like a catch-22.

    The other thing you lose with closures, though it's not in the JAR list, is the ability to serialize the object. Actually you're going to lose that any time you have actual protection.

    For another interesting Perl OO implementation, see Damian Conway's Std::Class (http://search.cpan.org/~dconway/Class-Std-v0.0.8/lib/Class/Std.pm), which he also calls "inside-out" classes. Essentially, the object consists of a token, and the object's data is registered against that token in the lexical space of each class or subclass. It's still taking advantage of closures in a way, it's just that all of a class's methods are named closures with exclusive access to the lexical class data. There are some minor practical problems in the actual implementation (see the RT tickets), but the abstract idea seems sound as far as providing true encapsulation and protection without making inheritance hard.

    Comment by sosiouxme — 30 May 2006 @ 08:43

  4. Frankly, I'm still trying to sort out why Christiansen bothered to apply bless() to a perfectly good example of a closure as an object. It's unnecessary and redundant. I think he might have been having trouble escaping the "objects need to be blessed" supposed truism of OOP in Perl. All bless() seems to provide is a package name (class) association, which can be specified as easily without use of bless() if you wish. Well, that, and it applies a whole new syntax to the reference being blessed — a syntax that is onerous and unnecessary to get objectlike behavior (even if it's more familiarly "object oriented" to some programmers).

    I'm curious how you mean that closures don't provide true encapsulation and protection. As far as I can tell, the only way you can figure out the data types being used internally by a closure is to destroy the closure by directly dereferencing and dumping its contents into something else — in which case you cease to have your closure "object", thus ending the circumstance within which encapsulation is applicable. Similar rules seem to apply to protection with regards to a closure "object". Sure, there's a way around it using a debugger as Christiansen suggests, but that is well outside the realm of OOP because you're talking about manually analyzing it with a debugger rather than discovering the implementation of a type through clever use of code. A debugger isn't part of the language, and if you're going to use external tools you could conceivably do the same thing with any object from any language using a hex editor and some clever analysis (which could in turn be performed by a program written in the same language, conceivably, if you like).

    The point of encapsulation and protection in object oriented programming is not to make it impossible for the programmer to see what an object is doing — which is easily circumvented in Perl just by reading the source code anyway. It's to keep an object distinct and "sacred" from the machinations of code that interfaces with it. Lexical closures perform that duty admirably, and in fact do so better than non-closure objects in Perl, as far as I can tell, by applying lexical scope then removing access to the scope from outside the "object" (aside from doing the Perl equivalent of manually pushing bits around in RAM, which applies to any and all objects in Perl).

    Considering that the whole point of an object seems to be that it's an atomic "thing" that maintains and manipulates state internally (whichever of the data and the methods you figure is central), there isn't a whole lot missing. The form of the data internal to the closure object (a hash, to which you make reference, is but one example, and is the one Christiansen employed in perltoot, but not the only example possible) is irrelevant to the code using the closure "object". You don't really get to interact with the hash: only with the subroutines attached to it ("procedures" in the most generic programming sense of the term — whether method, function, or subroutine, and whether primitive or defined, they're all procedures).

    I'm not sure why you'd want a subclass to add anything to its superclass's lexical space in an instantiated form, since a major point of objects is that they're supposed to be separate from and independent of external code. In what way do you intend for a subclass to modify a superclass's lexical space? For what purpose? How does that affect inheritance, which (as I understand it) involves passing some definitions of structure and functionality from a superclass to a subclass at instantiation?

    Far from being unwieldy, lexical closures as objects strike me as being much simpler and more elegant than objects according to the majority of what's in perltoot and other sources. There are a couple of things that become more of a pain in the butt to work with than with canonical Perl (non-closure) objects, but even in those cases it's largely because of the existence of stricter object-oriented behavior than you get without lexical closures.

    Inheritance occurs before compile-time in Perl — doesn't it? Assuming that's the case, it occurs before the coderef gets passed and lexically closed in a closure "object", so wrapping a closure "object" in some loose code for inheritance purposes seems redundant and unnecessary, designed more for making the more-traditional object oriented programmer comfortable with the way inheritance is represented than for making inheritance possible. Multiple inheritance might be another matter, as might mix-ins (I haven't thought it through that far yet). If mix-ins are possible, however, I find myself wondering if "true inheritance" is even desirable (depending on the manner in which mix-ins can be used). See Ruby for examples of what I mean here.

    I'm not sure what you mean about serializing an object. Please expand upon that. I'm not sure that's really appropriate for object oriented programming in principle if you lose it with protection of an object — it seems inherently at odds with the concept of OOP to specifically include a feature in the definition-menu of OOP that conflicts directly with other menu items — but I'm willing (even eager) to be educated.

    What I see happening in both Conway's and Christiansen's uses of lexical closures in an object model isn't use of closures as objects so much as an "enhancement" of Perl's canonical objects through clever use of closures. This makes sense in both cases, in Christiansen's because he wrote about OOP using bless() in perltoot (which is supposed to be about bless-objects anyway), and in Conway's because he was creating an "enhanced object model" module rather than simply discussing what's already there as I am. What I'm suggesting is a completely different approach entirely to an object model from the bless() model, wherein the closure is the object, period.

    Anton van Straaten makes an interesting case for lexical closures as being the equal of objects, in response to Guy Steele's mention of the debate over whether closures are a poor man's objects or objects are a poor man's closures. Considering you can get class namespace and object interface behavior with closures in Perl, without even using bless(), much of the argument in favor of objects as the "greater" of the two seems inapplicable in this language. Van Straaten is of course comparing Scheme's closures with something like Smalltalk's objects (though, in fact, he's more specifically talking about Java's objects, which are certainly a "poor man's objects" in comparison with those of Smalltalk), while I'm talking about Perl's closure-objects vs. Perl's bless-objects. Van Straaten ends up providing a koan in which either objects or lexical closures can be a knock-off of the other, depending on your needs and perspective at the time — taking each of them as a sort of Platonic ideal, each represented in a language that makes supposedly proper use of it. Since I'm speaking within the limited realm of a single language, however, a different situation arises: it looks like the (perceived) beneficial and definitional behavior of the "object" Platonic ideal is more fully realized with an appropriately instantiated closure-object than with an appropriately instantiated bless-object, where each is implemented entirely without the aid of the other.

    The more I learn about OOP, and the more gets driven home about lexical closures as they're implemented in Perl, the more convinced I am of the ability of lexical closures in the context of Perl to provide a complete object model that might do its job better than the canonical Perl object model using bless(). There's always still the potential for some fatal flaw to arise, but I have yet to see it.

    What I see from the OOP menu, applied to both object models, is this:

    1. encapsulation: stronger in closure-objects
    2. protection: stronger in closure-objects
    3. ad-hoc polymorphism: unknown (I'm unsure how this applies to each at present)
    4. parametric polymorphism: ditto what I said about ad-hoc
    5. everything is an object: equally applicable to both, since it seems both can only be an almost-exclusive means of making things happen in a Perl program
    6. AYCDISAM: probably leans in closure-objects' favor, if they differ at all in this
    7. specification inheritance: seems inapplicable with Perl's semidynamic typing
    8. implementation inheritance: roughly equivalently possible/capable for both
    9. sum-of-product-of-function: equivalent, since this is a language measure, not an object measure, and as long as each is capable of conforming to this restriction depending on implementation (rather than depending on instance), each is equally capable of providing a "true" object model

    With all that in mind, it looks to me like bless-objects are kind of superfluous in Perl.

    Comment by apotheon — 1 June 2006 @ 08:14

  5. As usual, I've made a muddle of concepts that were clear in my mind. Let me see if I can clarify.

    Frankly, I'm still trying to sort out why Christiansen bothered to apply bless() to a perfectly good example of a closure as an object.

    The only purpose of bless() is to find methods for an object — whether in the object's class directly or in a superclass. With a closure, you can just call the closure itself, so it does seem like you could dispense with bless() altogether — but that requires all of your logic to be accessed from within the closure. Perl's bless() and inheritance structure were always a bolt-on convenience; if you want to implement your own scheme for methods and inheritance, well, TMTOWTDI — but it's a lot of work.

    Alright, there's one more purpose of bless(), which is to be able to identify an object's type. Usually duck typing is all you need but sometimes you really need to know if an object is a Foo or a Bar. One reference looks quite like another if you do not bless() it.

    I'm curious how you mean that closures don't provide true encapsulation and protection.

    They do, inherently, but this is exactly what causes the complexity with inheritance. You might say that inheritance is simply adding to an existing class. You are adding or at least overriding behavior, and possibly adding data members as well. But closures are immutable, so they cause problems when you want to expand them into a subclass with more data members and behavior. I've changed my mind three times now on whether those problems were intractable under the OO rubric, concluding that indeed, closures can be used for inheritable objects, but perhaps not quite as elegantly as you hoped. And I wrote some code to prove it. Now, to explain how I got there:

    The first problem you face with inheriting in a closure model is where to put the added data members for the subclass. Your base class could contain all members in an expandable structure like a hash, as Christiansen did, but because your closure has the only access to the members, and cannot anticipate the needs of subclasses, it is basically forced to give (nearly) arbitrary access to data elements to all comers, which makes it no better than a plain hash as far as member protection.

    You could follow the route of Damian Conway's Std::Class and keep the members in the class lexical space with a closure as the key. I think this is the most elegant way, but then you're not using the closure for its ability to protect data members anyway, so why confuse the issue with a closure at all?

    The final way would be to actually use separate closures for the subclass and superclass, each containing that class's data members. This works fine, but now you've spawned a new problem: the subclass object now needs to wrap the superclass object (keeping it as a member and forwarding inherited calls to it), which is a bit tedious, and worse, the superclass object knows nothing about the subclass object (according to OO tenets) and can't easily access its overridden methods. To get around this, each closure call has to contain the original subclass object, which adds a bit to its ugliness.

    Now, there are still some items to dispatch. First, because only the closure has direct access to data members (and to maintain member protection, can't give out arbitrary access to those members), methods in the traditional Perl sense (that is, class subroutines) will not have access to those members, as they would in another language like Java. So all logic pertaining to data members must be accessed via the closure, which is a bit clunky: either the closure implements all the logic, or the closure just accesses members and sends them out to subroutines for the logic, or the closure implements a base set of logic upon which all class methods are built, or (elegantly but somewhat impractically) the methods could themselves be closures that capture the data members. None of those choices are particularly appealing to me, at least, but see my code for the first and last.

    Second, we have to consider whether and how to implement "isa" and "can" capabilities against our objects. "isa" is easy if we continue to bless our objects and specify heirarchy with @ISA, because UNIVERSAL::isa will take care of it — otherwise, each class and subclass must explicitly specify some kind of "isa" method of its own. "can" may be pretty tricky depending on how your object behavior is implemented, but I've never cared much about "can" so I'd not worry about the extra effort there personally.

    Now, to demonstrate what I mean, I've written a bit of code: a Person class with a $name member; an Employee subclass that adds the $job member; and a bit of code to use both. You might examine it here:

    http://sosiouxme.net/dl/Person.pl

    Note that I've chosen to implement both classes without standard Perl methods, rather letting AUTOLOAD convert those methods into closure calls. This requires the continued use of bless(), which along with @ISA means you get "isa" for free and greatly improves how method invocation looks. If you're interested, you might try modifying it to take bless() and @ISA out of the picture and see what changes — it's not hard, but illustrates what I mean. Also, if I've insufficiently explained why each closure call needs $self as an argument, see what happens when you remove that. How else might you improve this model? Does it seem elegant to you?

    I'm not sure what you mean about serializing an object. Please expand upon that. I'm not sure that's really appropriate for object oriented programming in principle if you lose it with protection of an object — It seems inherently at odds with the concept of OOP to specifically include a feature in the definition-menu of OOP that conflicts directly with other menu items — but I'm willing (even eager) to be educated.

    Serializability, as far as I know, isn't a required feature of OO. It really can't be, because it does compromise the principle of data protection. I assume you already know what serialization is, or can use wikipedia to find out. Serialization requires the ability for an external entity to access and set all meaningful internal state data of an object (... unless your class can serialize and deserialize itself, of course). The classic example is Storable; another one people don't think about much is Data::Dumper. Neither works with closures, because closures protect their contents. That makes it difficult to debug with Data::Dumper, and more importantly, means you could not store such objects in a web server session, access them across a web service, persist their state between executions of the same program, or various other useful things we frequently want to do in an OO setting.

    Thanks, this discussion gave me a lot to think about :-)

    Comment by sosiouxme — 4 June 2006 @ 12:13

  6. The only purpose of bless() is to find methods for an object — whether in the object's class directly or in a superclass.

    That seems to sorta agree with my impression of bless(): that it just creates namespace and syntax management in a manner familiar to many object oriented programmers.

    Alright, there's one more purpose of bless(), which is to be able to identify an object's type.

    How exactly does that work? I am apparently unfamiliar of that nuance of bless() functionality.

    You might say that inheritance is simply adding to an existing class. You are adding or at least overriding behavior, and possibly adding data members as well. But closures are immutable, so they cause problems when you want to expand them into a subclass with more data members and behavior.

    Maybe it's my relative lack of OOP experience speaking, but I was under the impression that proper inheritance was something that happened before (or, more precisely, during) instantiation as objects. As such, it seems to me that encapsulation and protection shouldn't interfere with it at all, since the closure is built with inheritance, rather than built then modified by inheritance. Classes can be objects, depending on how your language is designed, but from what I can see in Perl they are not: they are, instead, object "blueprints" from which objects are built, and as such do not have the problem of strict encapsulation and protection from the perspective of inheritance, as far as I can tell. It's entirely possible I'm misunderstanding something, though: for the most part, my experience of working with objects all involves using someone else's classes and objects through their interfaces without actually creating and dealing with class definitions and original object creation.

    Regarding the amount of code writing that needs to be done to get "standard" object behavior with closures (if one eschews bless(), that is), I've pretty much assumed there'd be a little more explicit scaffolding generation necessary for OOP with closure-objects rather than bless-objects, since some real work has gone into creating an object model with bless() in Perl. Meanwhile, the notion of using lexical closures as the basis of an object model has been all but ignored. As a result, a bolted-on kludge (specifically, bless() and friends) starts to look "more elegant" just because of the manner in which it has been extensively massaged, while the inherently fuctional (in the non-programming sense of the term) lexical closures of the language haven't even been "officially" identified as a basis for an object model, let alone finessed to automate any commonly-performed OOP tasks. That being the case, it's really kind of amazing that it provides as much OOP behavior as it does — enough that it's worth debating how the closure-object model compares with the bless-object model in terms of comparative benefits and elegance.

    I'm also of the impression that a closure-object model might provide a more elegant syntax for doing method calls and handing your instantiated object around the program than that more traditional to the bless-object model. For instance, $closure->('method') has potential as a means of calling a method.

    I've looked over your code, and I'm going to look over it some more (probably on a day when I don't have a possible online meeting, dishes to do, breakfast to eat, and a TT RPG to attend, in addition to the usual things I do day to day). I've been thinking about how to put together classes and objects using lexical closures as the basis for the object model for a week now, in terms of ideas for how to organize the code, but haven't actually gotten around to doing anything substantive. I'm being held back by a combination of laziness and not having a ready-made howto guide for it the same way there are howtos for the official Perl object model — and a bit by the fact that I'm not an OOP guru that just automatically knows everything his objects need to be able to do to be equivalently useful.

    I'm working on it, though.

    Comment by apotheon — 4 June 2006 @ 01:33

  7. Alright, there's one more purpose of bless(), which is to be able to identify an object's type. How exactly does that work? I am apparently unfamiliar of that nuance of bless() functionality.

    Well, bless() marks an object as belonging to a certain class (which is how method calls find the sub in the appropriate class for an object). You can turn this around and introspect the object with several mechanisms. One is the good old Perl ref() function, which returns the class you blessed an object into. But the tricky bit is that all bless()ed objects implicitly inherit from the UNIVERSAL class, which provides two methods, isa() and can(), which are thus available to all bless()ed objects. $obj->isa("Class") determines whether $obj is of type Class, either directly or as a subclass. $obj->can("method") determines whether $obj has a declared method called "method" somewhere in its class or superclasses (methods provided via AUTOLOAD don't count as declared methods, though).

    You can see in my code example that I called isa against my objects, though I never actually declared it as a method.

    Maybe it's my relative lack of OOP experience speaking, but I was under the impression that proper inheritance was something that happened before (or, more precisely, during) instantiation as objects.

    I'm not quite clear what you mean by when inheritance "happens". Inheritance is a behavior; when you invoke some behavior against an instance of some class and a superclass's behavior is invoked as a result, that's inheritance. In a strongly typed language designed with OO from the start, like Java, it doesn't make much sense to think of inheritance as a dynamic thing, but in Perl, where you can create whole class heirarchies at runtime, it absolutely is.

    I think you're looking at Perl OO as something a little more codified than it actually is. In a classic Perl OO model, a reference is not an object until something bless()es it, which occurs at runtime, and any code can choose at runtime to bless any reference into any class whatsoever, which just means that's where that object's method calls will look for subroutines. It's only by convention that we typically use a class constructor method named new() that allows subclasses to call it and bless()es the object accordingly into the class or subclass. In a classic Perl OO model, your superclass is whatever @ISA says it is, and you can change that at runtime if you're crazy enough to try, and the method lookups against your objects will follow. Data members are whatever you can find a way to identify with individual instances, and you can generate methods on the fly (per-class, not per-object, unfortunately) or handle methods that never actually exist with AUTOLOAD. Perl's OO mechanisms are total anarchy compared to most OO languages; they enforce no conventions at all, it's just that people tend to stick with conventions if they know what's good for them, and end up with behavior that appears OO.

    You're definitely right that closures show potential as an alternate OO mechanism, though. $closure->("method", @args) is more or less what I do in my example classes, though to enable inheritance it really needs to be $closure->($closure, method => @args). If you eschew the member-protection requirement (as the classic Perl OO model does) it becomes even easier. I think if you try putting together your own closure-based classes (or modifying my examples) a lot of things should become clearer.

    Comment by sosiouxme — 4 June 2006 @ 05:12

  8. Well, bless() [. . .]

    I'm not sure I see how any of that involves identifying an object's type.

    I'm not quite clear what you mean by when inheritance "happens". Inheritance is a behavior; when you invoke some behavior against an instance of some class and a superclass's behavior is invoked as a result, that's inheritance.

    This is how I understand it: Some set of inherited functionality is defined, in some way, as being part of the functionality of an object when it is instantiated. There are different ways this might happen, depending on the language and object model, and perhaps depending on the way the programmer makes it happen. It might be a set of "ancestors" from which an object can get certain methods if they don't exist within it when they're called, or they can be attached to it at instantiation time, for two examples. Is that fairly accurate?

    Of course, depending on how the code is compiled or interpreted, the way it appears to work from the programmer's point of view might be further diversified from the computer's point of view. Something that appears to be attached to an object during instantiation might in fact just be slotted in with a long list of things that are sorta indexed for later reference when the code is running with an interpreted language, and for a compiled language what looks like a dynamic call at runtime might conceivably be looked up and attached to the goings-on of a given object's use when it's compiled so that it behaves from the computer's perspective more like inherited methods were attached to the object directly.

    Maybe I'm just unnecessarily muddying the waters somehow, but ultimately my point is that I don't see how inheritance can be "blocked" by encapsulation since it can be something that effectively happens before the lexical space of a callback is closed by its parent going out of scope.

    Being able to create whole class hierarchies at runtime would also apply to being able to create them for closure-objects just as for bless-objects (though obviously the code used would be somewhat different). In the end, no matter how late you defer the inheritance behavior, the lexical closing can be deferred later if need be. That seems especially true if you eschew the use of bless() entirely with a closure-object model.

    I love this conversation, by the way. Thanks.

    Comment by apotheon — 4 June 2006 @ 11:13

  9. It wasn't clear to me how to respond to this, but I'd be interested in seeing if you've come up with any implementations of what you're talking about. In particular, I'm not sure what this means:

    In the end, no matter how late you defer the inheritance behavior, the lexical closing can be deferred later if need be.

    Because "lexical" scope is by definition restricted to the actual text you write, lexical closing is restricted to what you write in the text of your base class. The text you write must anticipate and account for any kind of inheritance you expect it to do at the time you write it, but without specific knowledge of any future subclasses. I'm not sure how you can "delay" the closing of lexical scope, other than by creating a new scope with your subclass, with all the attendant difficulties I mentioned — or perhaps you were thinking of actually generating the text of your lexical scope and closure at run-time with an eval? I'd really like to see what you've come up with on this, though.

    Comment by sosiouxme — 17 June 2006 @ 01:22

  10. Frankly, I'm still not quite expert enough with Perl to be able to do that with any confidence yet, so I'm going to leave it alone for a while. I'll probably come back to it. I've already left it alone for a while (obviously), but as of now I think I'll go post something new to demonstrate a simple, brain-dead object via a closure-object model.

    Comment by apotheon — 1 August 2006 @ 02:31

  11. [...] Many many moons ago, SOB (that's where you are now) hosted a discussion of the idea of an object model based on lexical closures for the Perl programming language. Blame the sugar, or the fact I've been sleeping poorly, or whatever you like, but I'm going to make a half-baked attempt at actually demonstrating the creation of a class, with methods, plus instantiation of the closure-object and passing messages to it. [...]

    Pingback by SOB: Scion Of Backronymics » Example Class and Instantiation of Perl Closure-Object — 1 August 2006 @ 03:03

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

All original content Copyright Chad Perrin: Distributed under the terms of the Open Works License