http://www.perlmonks.org?node_id=1043097

tobias_hofer has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks,

I have wrapped the access to a hardware-debugger in a perl module. I have not implemented it in OO-Style (to access stuff by the $self reference i.e.), so a call to GetInstance will return the package-local variable which is the handle to the Win32-OLE Debugger instance. But using the debugger by the variable outside the package breaks and the varialble turns out to be a unblessed reference. Why?

When I am using the debugger by the variable inside the package its working fine.

UPDATE: once $debugger is initialized it is a blessed reference to the OLE Object

Here the code snippets

package myDebugger; use strict; use warning; use Win32; use Win32::OLE; use Win32::OLE qw( in with ); use Win32::OLE::Const 'UDE'; ... my $debugger; sub GetInstance { if ( defined $debugger) { return $debugger; } else { #Initialize Debugger and set $debugger DebuggerInit(); (defined $debugger) ? return $debugger : print "Can't initialize debugger, please check!" ); return 0; } }

Any help and advice is highly welcome!

Best regards!
Tobias

Replies are listed 'Best First'.
Re: Singleton and unblessed refereces.
by rjt (Curate) on Jul 08, 2013 at 12:16 UTC

    Works for me with dummy objects:

    test.pl:

    #!/usr/bin/env perl use 5.012; use warnings; use myDebugger; my $instance = myDebugger::GetInstance(); say ref($instance); $instance->{foo} = 'Persistent'; # Ensure we get same instance my $instance_ref2 = myDebugger::GetInstance(); say ref($instance_ref2); say $instance_ref2->{foo};

    myDebugger.pm:

    package myDebugger; use 5.012; use warnings; my $debugger; sub GetInstance { return $debugger //= bless { foo => 'bar' }, 'OLEThingy'; } 1;

    Output:

    OLEThingy OLEThingy Persistent

    I suggest you eliminate this code and focus on the object in question; boil it down to a small test case, and the problem might solve itself, or you can of course come back here armed with more information.

Re: Singleton and unblessed refereces.
by kcott (Archbishop) on Jul 09, 2013 at 07:29 UTC

    G'day Tobias,

    Problems with what you've posted:

    • You haven't shown what DebuggerInit() does.
    • You haven't shown how you run this code.
    • There's no self-contained script that we can run to reproduce the problem.
    • You don't show actual or expected output nor any error (or other) messages.

    Having said that, declaring $debugger as being scoped to the entire package leaps out at me as being a potential source of problems (either now or in the future). Consider this scenario:

    $ perl -Mstrict -Mwarnings -le ' package myDebugger; my $debugger; sub GetInstance { defined $debugger ? $debugger : DebuggerInit() } sub DebuggerInit { $debugger = "singleton" } # a typo later in your code (perhaps "$debug = 0;" was intended) my $debug = 1; # ... $debugger = 0; package main; print myDebugger::GetInstance(); print myDebugger::GetInstance(); ' 0 0

    Now see what happens if the scope is changed such that only GetInstance() and DebuggerInit() can see $debugger:

    $ perl -Mstrict -Mwarnings -le ' package myDebugger; { my $debugger; sub GetInstance { defined $debugger ? $debugger : DebuggerInit +() } sub DebuggerInit { $debugger = "singleton" } } # a typo later in your code (perhaps "$debug = 0;" was intended) my $debug = 1; # ... $debugger = 0; package main; print myDebugger::GetInstance(); print myDebugger::GetInstance(); ' Global symbol "$debugger" requires explicit package name at -e line 11 +. Execution of -e aborted due to compilation errors.

    Fixing the typo (at line 11):

    $ perl -Mstrict -Mwarnings -le ' package myDebugger; { my $debugger; sub GetInstance { defined $debugger ? $debugger : DebuggerInit +() } sub DebuggerInit { $debugger = "singleton" } } # a typo later in your code (perhaps "$debug = 0;" was intended) my $debug = 1; # ... $debug = 0; package main; print myDebugger::GetInstance(); print myDebugger::GetInstance(); ' singleton singleton

    Please create a minimal, self-contained script that reproduces your problem as described in the "How do I post a question effectively?" guidelines. As ++rjt has pointed out, by doing this you may resolve the problem on your own. If you need further help, please also include the missing information I alluded to above and also described in the guidelines I've linked to.

    -- Ken

      Hi,

      Sorry for my late replay.
      I still have not found the root-cause.
      I made an example where i replaced the OLE-interfaced debugger by the OLE-interface of the excel application (because I do not suppose someone has a PLS UDE debugger at home) and it is working fine - its completely bizzare to me. However, if i am doing the same with the debugger OLE Application i get the $debugger variable as undefined.

      Please have a look

      Here my example code:

      TestMe.pl
      ########################################## #Perl file which shall use the "debugger" ########################################## use strict; use warnings; use diagnostics; use myDebugger; my $_db = GetInstance(); print "Does not work\n" if (not defined $_db); print "Is working fine\n";
      myDebugger.pm
      ########################################## #Perl file myDebugger.pm ########################################## package myDebugger; use strict; use warnings; use Win32::OLE; use Win32::OLE::Const "Microsoft Excel"; use Win32::OLE qw(in with); use Win32::OLE::Variant; use vars qw($VERSION $HEADER @ISA @EXPORT); use Exporter; $VERSION = q$Revision: 1.1 $; $HEADER = q$Header: Some CMS data... $; @ISA = qw(Exporter); @EXPORT = qw( GetInstance ); # export subs my $debugger = undef; sub GetInstance { if ( defined $debugger ) { return $debugger; } else { DebuggerInit(); defined $debugger ? return $debugger : print " Init error!"; return 0; } } sub DebuggerInit { # Instead of an Debugger, I use here the Excel-Application. # Both excel and the debugger application are interfaced by OLE # Thus I think its a good replacement as an example. # Also the way how the OLE Application is the same # as the originally used UDE PLS Debugger. $debugger = Win32::OLE->GetActiveObject('Excel.Application'); unless ($debugger) { $debugger = new Win32::OLE( 'Excel.Application', \&main::QuitA +pp ); } } sub main::QuitApp { exit(); } 1;

        I would add far more checks/tracing to DebuggerInit. Maybe ->GetActiveObject() does differ in behaviour for the debugger, or creating the new object fails if the debugger application is not already running. Output the functions called and the results in DebuggerInit.

        Your choice of setting up a call to exit() in the object destructor:

        $debugger = new Win32::OLE( 'Excel.Application', \&main::QuitApp );

        ... strikes me as weird. I use the call to properly tear down the OLE object, and not to exit the Perl script in a very hard way. Maybe the debugger application does not like that method of improper cleanup. As a first start, I would not try to quit the OLE application at all upon script exit. This will likely leave you with headless processes accumulating, at least it does with Excel. After trying that, I would look at finding the proper way to quit the debugger application. Maybe you need to do nothing, or you need to do the same thing that the Win32::OLE documentation suggests, except in the appropriate way for your debugger:

        $ex = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;}) # calls $ex->Quit() when the Perl program ends or $ex goes out of +scope

        As a personal style option, I would not cache the $debugger in a file-global lexical variable. In most cases, using a proper global variable in the packages is better for me, because it allows me to explicitly undef such variables for debugging purposes.