http://qs321.pair.com?node_id=504425

After several weeks of intense development, I feel comfortable in releasing (unleashing?) a new module on CPAN: Object::InsideOut

Object::InsideOut provides comprehensive support for implementing classes using the inside-out object model.

It implements inside-out objects as anonymous scalar references that have been blessed into a class with the scalar containing the ID for the object (usually a sequence). Object data (i.e., fields) are stored in arrays within the class's package and are indexed on the object's ID.

This module offers all the capabilities of Class::Std with the following additional key advantages:

Rationale:
Prior to the publication of Perl Best Practices, I came across discussions of inside-out objects here on Perl Monks, and I liked the concept so much that I converted my other module (Math::Random::MT::Auto) to using inside-out objects, including tackling the problem of using inside-out objects in threaded code (i.e., use threads;).

With the release of Perl Best Practices, I looked at converting Math::Random::MT::Auto to using Class::Std instead of my own inside-out object support code. To my dismay, I found that Class::Std was not thread-safe. Further, its object structure (empty scalar ref) and single method of determining object IDs (refaddr) were incompatible with what I had written.

While I laud Damian Conway for the work he did on Class::Std, its slowness (due to calculating the object ID at every turn), lack of thread support, and inflexibilities (lack of support for user-supplied object ID, accessor naming conventions, and so on) lead me to further development of my inside-out support code. In overcoming these deficiencies, the resulting module architecture was such that it could not be combined with Class:Std, and thus required the issuance of an new and separate module to CPAN.

As part of the development of this module, I made sure that it incorporated all of the functionality of Class::Std so that there would be no want for using this module. Further, I discovered that, unlike hash-based objects, it was possible to share scalar-based objects between threads when using threads::shared.

All in all, I feel that Object::InsideOut provides comprehensive support for the development of inside-out object classes that provides speed and flexibility, as well as the capability to work with objects in a threaded application complete with object sharing, if needed.

Plea:
I would like to invite my fellow monks to look at what I've developed. Hopefully, some of you may find it useful. I would, of course, appreciate any critiques, suggestions, ideas, etc. that you might have. Thank you.

Update:
The lastest version of Object::InsideOut supports using arrays for storing object field data. This resulted in an impressive speed improvement (mentioned above) that I hope will be a further incentive to my fellow monks to give Object::InsideOut a try.


Remember: There's always one more bug.

Replies are listed 'Best First'.
Re: New Module Announcement: Object::InsideOut
by Ovid (Cardinal) on Nov 01, 2005 at 00:01 UTC
      Thank you for bringing this to my attention. I have developed a solution for this issue and have uploaded it to CPAN. The solution entailed packaging all the CHECK phase code into a subroutine. For regular usage, this will get run during the CHECK phase.

      For code run under mod_perl, or code that is loaded at runtime using require, the subroutine will be called when the first object is created.

      In all cases, initialization occurs as necessary and is completely transparent.

      I was not able to test this under mod_perl, but it works properly for runtime loaded code.

      Remember: There's always one more bug.
Re: New Module Announcement: Object::InsideOut
by xdg (Monsignor) on Nov 01, 2005 at 02:02 UTC

    Kudos! I'm very happy to see more work done in this area, particularly that which addresses some of the glaring shortcomings of Class::Std. I look forward to studying it in more detail.

    One point of note -- by storing the id in the blessed scalar, you eliminate the ability of an inside-out object to subclass any kind of object. That is one of the two main benefits of inside-out objects (the other being privacy). (See various threads in Threads and fork and CLONE, oh my!). It's at least worth noting in your documentation as you're using a more specific variation of the inside-out technique that trades speed for some flexibility of design.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      by storing the id in the blessed scalar, you eliminate the ability of an inside-out object to subclass any kind of object
      True. In addition, the nature of the new method in both Object::InsideOut and Class::Std also precludes this capability.

      Remember: There's always one more bug.
        As of v1.18, Object::InsideOut supports inheritance (i.e., sub-classing) of non-inside-out object classes.

        Remember: There's always one more bug.
Re: New Module Announcement: Object::InsideOut
by BrowserUk (Patriarch) on Nov 01, 2005 at 04:21 UTC

    I tried to build this on AS810 (5.8.4) and I am getting test failures in 03-threads.t.

    Tracing the testscript through, the failure appears to be when the test for is_sharing() is called at InsideOut.pm(388):

    # Share the hash, if applicable if (is_sharing($pkg)) { threads::shared::share($hash) }

    and

    sub is_sharing : PRIVATE { my $class = $_[0]; # If not 'use threads::shared;', return false if (! $threads::shared::threads_shared) { return; } return ($IS_SHARING{$class}->[0]); }

    The if suceeds, so the function returns undef with the result that the hash is not shared.

    Without claiming to have read or traced every line, I cannot see anywhere in InsideOut.pm where threads::shared is ever used or required. What am I missing?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      All the failures you received were due to your not having Exception::Class installed ("Can't locate Exception/Class.pm in @INC"), and had nothing to do with the presense or absense of threads::shared.

      As to your question concerning threads::shared, it is documented in the POD, namely, the application must use threads::shared;. t/03-threads.t is testing threads without object sharing and thus does not use threads::shared. However, t/04-shared.t does. Hope that helps.


      Remember: There's always one more bug.

        I do apologise, it appears I c&p'd the wrong log. This is the one I should have posted

        C:\Perl\packages\Object-InsideOut-0.02.00>perl -MException::Class -wle +"print $Exception::Class::VERSION" 1.22 C:\Perl\packages\Object-InsideOut-0.02.00>nmake test Microsoft (R) Program Maintenance Utility Version 8.00.40607.16 Copyright (C) Microsoft Corporation. All rights reserved. C:\Perl\bin\perl.exe "-MExtUtils::Command::MM" "-e" "test_harn +ess(0, 'blib\lib', 'blib\arch')" t\01-basic.t t\02-auto.t t\03-thread +s.t t\04-shared.t t\01-basic......ok t\02-auto.......ok t\03-threads....ok 3/12thread failed to start: Can't locate object met +hod "x" via package "UNIVERSAL" at t\03-threads.t line 48. t\03-threads....ok 5/12# Looks like you planned 12 tests but only ran +6. t\03-threads....dubious Test returned status 6 (wstat 1536, 0x600) DIED. FAILED tests 7-12 Failed 6/12 tests, 50.00% okay t\04-shared.....ok Failed Test Stat Wstat Total Fail Failed List of Failed ---------------------------------------------------------------------- +--------- t\03-threads.t 6 1536 12 12 100.00% 7-12 Failed 1/4 test scripts, 75.00% okay. 6/53 subtests failed, 88.68% oka +y. NMAKE : fatal error U1077: 'C:\Perl\bin\perl.exe' : return code '0xff' Stop.

        As you can see, I have installed Exception::Class, but I am still getting failures from 03threads.t


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: New Module Announcement: Object::InsideOut
by Aristotle (Chancellor) on Oct 31, 2005 at 21:40 UTC

    Neat. I like the idea of using $$self to avoid the constant ident $self calls.

    I took only a cursory look, but so far I like what I’m seeing.

    Makeshifts last the longest.

Re: New Module Announcement: Object::InsideOut
by Errto (Vicar) on Nov 01, 2005 at 02:45 UTC
    Seems pretty neat. One little technical question: in the second example in the SYNOPSIS, how does it know that the 'INFO' argument to new() corresponds to the %info hash? As I read it you would need to add 'Field' => \%info to the initArgs hash to do that.
      Thanks. I'll correct that in the next release.

      Remember: There's always one more bug.
Re: New Module Announcement: Object::InsideOut
by diotalevi (Canon) on Nov 03, 2005 at 16:18 UTC

    Did you cover this test case? That ${} dereferencing (or actually, anything) is still legal? That numfication still worked correctly?

    use Test::More tests => 2; my $obj = Foo::Bar->new; is( $obj->some_method, "ok" ); is( 0 + $obj, 42 ); package Foo::Bar; use overload '${}' => 'some_method' '0+' => 'numify'; use Object::InsideOut; sub numify { 42 } sub some_method { "ok" }
      Because the object ID is stored in the object's scalar ref (i.e., $$self), overloading ${} deferencing is not allowed. I document this fact in the POD.

      However, all other forms of object deferencing through overloading are supported: Stringify, numerify, boolify, arrayify, hashify, globify and codify. Object::InsideOut simplifies defining these operations through the use of subroutine attributes. For example, your code would become:

      use Test::More 'no_plan'; package Foo::Bar; { use Object::InsideOut; sub numify :Numerify { 42 } } package main; my $obj = Foo::Bar->new(); is(0 + $obj, 42);

      Remember: There's always one more bug.
        If you treat the scalar as an opaque object, store nothing inside it and use overload::StrVal as the key instead, you can allow ${} to be overloaded as well. Data::Postponed uses blessed scalars as the object and allows anything what so ever to be overloaded.
Re: New Module Announcement: Object::InsideOut
by polettix (Vicar) on Jan 10, 2006 at 11:45 UTC
    I'd make it clearer in the documentation that you can safely access data using $$self for read reasons. Current docs concentrate in setting values, not getting, and I had my hard time to find something corresponding to the suggested ->set() method.

    I needed this mainly to build up a private accessor for a member variable. Which leads to a little feature request: would it be possible to automate the creation of private/protected methods? Or, if already present... would it be possible to read it clearly in the docs?

    Flavio
    perl -ple'$_=reverse' <<<ti.xittelop@oivalf

    Don't fool yourself.
      I'd make it clearer in the documentation that you can safely access data using $$self for read reasons.
      Okay. I'll do that.
      Would it be possible to automate the creation of private/protected methods?
      I just added this capability in v1.29 based on a user's suggestion (yours perhaps?). It's documented in the POD.

      Remember: There's always one more bug.