Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

macros: return or exit

4 views
Skip to first unread message

Marc Girod

unread,
Jan 21, 2010, 5:25:01 AM1/21/10
to
Hello,

I consider making a change to a module, which will significantly alter
its client interface.
Until now, client functions could exit, die, or exec: no further
action was meant to take place.
Alternatively, they could return 0, and a generic behaviour would
follow.

I want now to introduce a loop, i.e. to retain control.
I control one such client, and am not sure whether there are actually
more than one other.

My problem is however to maintain a branch of the module and its known
clients, at least in order to investigate it and possibly to get
feedback. This could take a year or so. Or more.

What I did in the main loop, is:

< my $rc = &$cmd(@ARGV);
< # ... and exit unless it returned zero.
< exit $rc if $rc;
---
> my ($rc, $done) = &$cmd(@ARGV);
> # ... and return unless it returned zero and not done.
> return $rc if $done || $rc;

The change in the client code is thus ( a couple of examples out of
many):

< exit $?;
---
> return($?, 'done');

or

< $lsp->exec;
---
> return($lsp->system, 'done');

etc.
What are my best options to handle this?
I could sketch a few overrides such as e.g. for 'exit':

$legacy? exit $_ : return($_, 'done');

...but this ought to be a macro, not a function, for 'return' to
return to the right context.
What should I look for in CPAN or in the FAQ?
How to make my question shorter so that it fits in such a query?

If you are curious (you are fully entitled to), the modules are (on
CPAN):
ClearCase::Wrapper (the base module)
ClearCase::Wrapper::MGi (my own client)
ClearCase::Wrapper::DSB (the other known client)

Thanks,
Marc

Ben Morrow

unread,
Jan 21, 2010, 8:14:01 AM1/21/10
to

Quoth Marc Girod <marc....@gmail.com>:

>
> I consider making a change to a module, which will significantly alter
> its client interface.
> Until now, client functions could exit, die, or exec: no further
> action was meant to take place.
> Alternatively, they could return 0, and a generic behaviour would
> follow.
>
> I want now to introduce a loop, i.e. to retain control.
> I control one such client, and am not sure whether there are actually
> more than one other.
>
> My problem is however to maintain a branch of the module and its known
> clients, at least in order to investigate it and possibly to get
> feedback. This could take a year or so. Or more.

It's not clear what procedure you're trying to follow here. Are you
going to create your own fork of the module, and possibly try to feed
the changes upstream, or are you trying to find a way to avoid that?

> What I did in the main loop, is:
>
> < my $rc = &$cmd(@ARGV);

The syntax $cmd->(@ARGV) is usually clearer, and generalises better to
situations like $cmd{$which}->(@ARGV).

> < # ... and exit unless it returned zero.
> < exit $rc if $rc;
> ---
> > my ($rc, $done) = &$cmd(@ARGV);
> > # ... and return unless it returned zero and not done.
> > return $rc if $done || $rc;
>
> The change in the client code is thus ( a couple of examples out of
> many):
>
> < exit $?;
> ---
> > return($?, 'done');
>
> or
>
> < $lsp->exec;
> ---
> > return($lsp->system, 'done');
>
> etc.
> What are my best options to handle this?

One option is to accept that the module you are using will terminate the
process, and fork before calling it in order to retain control. You will
need to think carefully about whether the exit calls are going to do
anything unpleasant to your filehandle buffers.

> I could sketch a few overrides such as e.g. for 'exit':
>
> $legacy? exit $_ : return($_, 'done');
>
> ...but this ought to be a macro, not a function, for 'return' to
> return to the right context.
> What should I look for in CPAN or in the FAQ?

Perl doesn't have macros, I'm afraid. If you can afford to maintain a
fork of the module, a simple search-and-replace in your text editor
would seem the easiest option.

Otherwise, one nasty option (and you're pretty much into nasty options
if you need to wrap a module with such an unpleasant interface) would be
to use the (undocumented and unexported) Want::double_return function
provided you the Want module. This sets up the next return to return
'twice', so you could do something like

require Want;
*Nasty::Module::exit = sub {
my ($rv) = @_;
Want::double_return();
return $rv, "done";
};

This would need to be done before loading Nasty::Module, so the override
gets properly picked up.

Ben

Marc Girod

unread,
Jan 21, 2010, 10:01:40 AM1/21/10
to
Thanks Ben,

On Jan 21, 1:14 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> It's not clear what procedure you're trying to follow here. Are you
> going to create your own fork of the module, and possibly try to feed
> the changes upstream, or are you trying to find a way to avoid that?

It is not clear to me.
I'll make my choice based on the options.
If I maintain a branch, I won't publish it to CPAN: I'll keep it in my
Google Code site.
Until I have something good enough to convince the author?
Earlier if the solution is not invasive?
Never if it ends up shooting the performance down or similar.

> The syntax $cmd->(@ARGV) is usually clearer, and generalises better to
> situations like $cmd{$which}->(@ARGV).

Thanks. I agree.
I'll remember it if I push a change to the base module.

> One option is to accept that the module you are using will terminate the
> process, and fork before calling it in order to retain control. You will
> need to think carefully about whether the exit calls are going to do
> anything unpleasant to your filehandle buffers.

I don't think it is an option: I already have one fork, and I'd very
much like the forked process to remain a single shared background
server.
And it is a proprietary binary, to which I talk via stdin/stdout (I
mean that it won't 'select').

> Perl doesn't have macros, I'm afraid.

This far, I knew...

> If you can afford to maintain a fork of the module,
> a simple search-and-replace in your text editor
> would seem the easiest option.

Many nasty merges for every change I'll do...
Or generate the branched version every time? Not impossible...
But double testing... double environment, double installs...

> Otherwise, one nasty option (and you're pretty much into nasty options
> if you need to wrap a module with such an unpleasant interface) would be
> to use the (undocumented and unexported) Want::double_return function
> provided you the Want module. This sets up the next return to return
> 'twice', so you could do something like

Should I say that this is exactly the kind of answer I was hoping?
I have to investigate it a bit.
It even seems like an example for making my own, if I could not use
this
one precisely...

Thanks again.
Marc

Uri Guttman

unread,
Jan 21, 2010, 11:37:02 AM1/21/10
to
>>>>> "MG" == Marc Girod <marc....@gmail.com> writes:

MG> And it is a proprietary binary, to which I talk via stdin/stdout (I
MG> mean that it won't 'select').

huh? do you mean select as in the single arg select which handle
gets print by default? or 4 arg select which multiplexes handles for
i/o? if you mean the 4 arg, you can definitely use that on the subproc's
stdio as that is a common way to manage i/o from a forked process.

uri

--
Uri Guttman ------ u...@stemsystems.com -------- http://www.sysarch.com --
----- Perl Code Review , Architecture, Development, Training, Support ------
--------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------

Marc Girod

unread,
Jan 21, 2010, 1:31:01 PM1/21/10
to
On Jan 21, 4:37 pm, "Uri Guttman" <u...@StemSystems.com> wrote:

> huh?

Sorry for the confusion.
The problem is probably that I didn't explain what binary I was
talking about.
I don't know how to make this story short, and it goes beyond our
scope.
If you are interested, you can read the docs on CPAN, for the modules
I mentioned, plus ClearCase::Argv which they all use.
But I doubt it is worth your interest unless you may try them, and
this depends on your having access to a ClearCase installation...

Marc

Uri Guttman

unread,
Jan 21, 2010, 1:41:01 PM1/21/10
to
>>>>> "MG" == Marc Girod <marc....@gmail.com> writes:

MG> On Jan 21, 4:37�pm, "Uri Guttman" <u...@StemSystems.com> wrote:
>> huh?

MG> Sorry for the confusion.
MG> The problem is probably that I didn't explain what binary I was
MG> talking about.

it is irrelevant about which binary. the issue is how do you manage its
i/o via its stdio. that is the same problem for any binary subprocess
you want to run with its stdio. now you never answered the question
about which select function you meant.

MG> I don't know how to make this story short, and it goes beyond our
MG> scope. If you are interested, you can read the docs on CPAN, for
MG> the modules I mentioned, plus ClearCase::Argv which they all use.
MG> But I doubt it is worth your interest unless you may try them, and
MG> this depends on your having access to a ClearCase installation...

no chance in hell of my having clearcase. :)

Marc Girod

unread,
Jan 21, 2010, 2:08:35 PM1/21/10
to
On Jan 21, 6:41 pm, "Uri Guttman" <u...@StemSystems.com> wrote:

> it is irrelevant about which binary. the issue is how do you manage its
> i/o via its stdio. that is the same problem for any binary subprocess
> you want to run with its stdio. now you never answered the question
> about which select function you meant.

The C function that the cleartool binary does not use.

I was not saying my code doing select in any way. I meant its *not*
doing select.
It may be me who do not understand...
If I fork part of my script, there will be two instances sharing the
same background process.
I cannot see this work.

Does it make better sense now?

Thanks,
Marc

Uri Guttman

unread,
Jan 21, 2010, 2:33:20 PM1/21/10
to
>>>>> "MG" == Marc Girod <marc....@gmail.com> writes:

MG> On Jan 21, 6:41�pm, "Uri Guttman" <u...@StemSystems.com> wrote:
>> it is irrelevant about which binary. the issue is how do you manage its
>> i/o via its stdio. that is the same problem for any binary subprocess
>> you want to run with its stdio. now you never answered the question
>> about which select function you meant.

MG> The C function that the cleartool binary does not use.

MG> I was not saying my code doing select in any way. I meant its *not*
MG> doing select.
MG> It may be me who do not understand...
MG> If I fork part of my script, there will be two instances sharing the
MG> same background process.
MG> I cannot see this work.

MG> Does it make better sense now?

not at all. when you fork, why not pass some flag to tell one of the
procs not to deal with the background process? in the other process,
close off the handles to that background process.

Marc Girod

unread,
Jan 21, 2010, 3:41:09 PM1/21/10
to
On Jan 21, 7:33 pm, "Uri Guttman" <u...@StemSystems.com> wrote:

> not at all. when you fork, why not pass some flag to tell one of the
> procs not to deal with the background process? in the other process,
> close off the handles to that background process.

Not to deal with the background process ?
But what should it do then ?
The whole purpose is to interface it !

It could compute pi decimals, or have dinner.
Once it has a fork...

Marc

Ben Morrow

unread,
Jan 21, 2010, 6:29:05 PM1/21/10
to

Quoth Marc Girod <marc....@gmail.com>:

>
> If I fork part of my script, there will be two instances sharing the
> same background process.

Well, my suggestion was that given

sub Nasty::Module::foo {
do_stuff(@_);
exec "some", "command";
}

you could call it like this

sub My::call_foo {
my $pid = fork;
defined $pid or die "can't fork: $!";

if ($pid) {
waitpid $pid, 0;
return $?;
}
else {
Nasty::Module::foo(@_);
}
}

The 'waitpid' ensures that you only call one function in Nasty::Module
at a time, and wait for it to exec and for the exec'd process to finish
before returning the status to the caller. It's equivalent to replacing
'exec' with 'system' as you originally suggested: system looks more or
less like

sub system {
if (my $pid = fork) {
waitpit $pid, 0;
return $?;
}
else {
exec @_;
}
}

except with some additional signal handling and so on.

Does this seems a reasonable approach now, or is there reason this is
impossible?

Ben

Uri Guttman

unread,
Jan 21, 2010, 7:46:23 PM1/21/10
to
>>>>> "MG" == Marc Girod <marc....@gmail.com> writes:

MG> On Jan 21, 7:33 pm, "Uri Guttman" <u...@StemSystems.com> wrote:
>> not at all. when you fork, why not pass some flag to tell one of the
>> procs not to deal with the background process? in the other process,
>> close off the handles to that background process.

MG> Not to deal with the background process ?
MG> But what should it do then ?
MG> The whole purpose is to interface it !

MG> It could compute pi decimals, or have dinner.
MG> Once it has a fork...

i am lost as to the big picture now. i either need to read all the older
emails again or you need to explain your goals (and not your
design). you seem to want to run some binary process and manage its
i/o. why does this need to be in the background? what about a simple
fork of it and manage its i/o in an event loop in the parent? this is
fairly easy and there are modules that do all the hard lifting. if this
design isn't good enough explain why you need a more complex
architecture.

Marc Girod

unread,
Jan 22, 2010, 3:31:44 AM1/22/10
to
On Jan 22, 12:46 am, "Uri Guttman" <u...@StemSystems.com> wrote:

> i am lost as to the big picture now.

I am not surprised, and I plead guilty.
But I am not writing something from scratch, and I am not going to
redesign anything too drasticly: I play as if there would be users,
and unpublished packages built upon this framework, which has been
public for many years.

So, I did describe my goals, and you did help me.
I appreciate that it is frustrating, after providing useful answers,
and already investing some effort, to be replied RTFM, or "sorry, I
won't disclose more".
It is just that I don't know where to cut: whereever I do, there will
be a next scope. For quite a long time.
Thanks.
Marc

Marc Girod

unread,
Jan 22, 2010, 3:45:32 AM1/22/10
to
On Jan 21, 11:29 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> Does this seems a reasonable approach now, or is there reason this is
> impossible?

I get it now: there will only be one instance.
However, it still poses some hard problems--although I can see that
you (collective of course) are not short of resources...

I'll have to take care that the pipes get properly transfered to the
child,
so that the communication goes on.
But, then, I maintain a reference count of (objects) clients of the
background server. There may be several per function, and the number
is dynamic. The last one turns the light off (send a 'quit' to the
server).
Well... the child will inherit the current count, and after it
completes, the count should drop back to where it was...?

I cannot turn this suggestion down: it seems valid too.
And maybe better than the first?
Forking is relatively expensive, though? The first should be faster?

Thanks again...
Food to thought. I should try and measure... Work... (No, that wasn't
Yuk!)

Marc

Marc Girod

unread,
Jan 24, 2010, 3:03:34 PM1/24/10
to
On Jan 21, 1:14 pm, Ben Morrow <b...@morrow.me.uk> wrote:

>     require Want;
>     *Nasty::Module::exit = sub {
>         my ($rv) = @_;
>         Want::double_return();
>         return $rv, "done";
>     };
>
> This would need to be done before loading Nasty::Module, so the override
> gets properly picked up.

OK. I installed Want, and it works on a demo example but so far not in
my test case.
I had to compile without -fstack-protector, which probably requires a
newer compiler than the one I have on cygwin. It may also be that this
would not be supported on cygwin or whatever.
Anyway, as I told, my demo seems to work, and all the tests passed.

The main problem is however that I can see now that double_return is
too unflexible: exit, exec and die may be invoked at any depth level
in the call stack, not necessarily at level 2.
What I would need with this strategy is a longjump...
I may still try to write it myself...

Or to investigate the other option: based on fork...

Marc

Uri Guttman

unread,
Jan 24, 2010, 3:35:26 PM1/24/10
to
>>>>> "MG" == Marc Girod <marc....@gmail.com> writes:

MG> The main problem is however that I can see now that double_return is
MG> too unflexible: exit, exec and die may be invoked at any depth level
MG> in the call stack, not necessarily at level 2.
MG> What I would need with this strategy is a longjump...
MG> I may still try to write it myself...

again, i am baffled as to your big picture. one day ...

but longjump in perl is spelled die/eval. if you wrap your stack of calls
with eval blocks, you can pop up the stack with dies until you hit the
one that handles that particular die. you can tell by passing in a die
string and checking it at each eval and propogating it up if it isn't
handled there.

Marc Girod

unread,
Jan 25, 2010, 4:57:54 AM1/25/10
to
On Jan 24, 8:35 pm, "Uri Guttman" <u...@StemSystems.com> wrote:

> >>>>> "MG" == Marc Girod <marc.gi...@gmail.com> writes:

> again, i am baffled as to your big picture. one day ...

'Big picture' is a philosophical assumption.
In general, there is none. What there are, are bigger pictures,
but they depend upon where you start.
So, we'd have to agree on a starting point, and learn gradually
what hidden (to us) assumptions we made, and why they break.

> but longjump in perl is spelled die/eval. if you wrap your stack of calls
> with eval blocks, you can pop up the stack with dies until you hit the
> one that handles that particular die. you can tell by passing in a die

> string and checking it at each eval and propagating it up if it isn't
> handled there.

Thanks again. This is a very valid answer.
I recognize it as something I knew, and didn't think of:
shame on me! I like this sens of after-the-fact obviousness.
I can very well investigate this path...

Marc

Marc Girod

unread,
Feb 21, 2010, 2:23:40 PM2/21/10
to
Hello,

I am only now back to this old thread of mine,
and to investigating Uri's suggestion...

On Jan 25, 9:57 am, Marc Girod <marc.gi...@gmail.com> wrote:
> On Jan 24, 8:35 pm, "Uri Guttman" <u...@StemSystems.com> wrote:

> > but longjump in perl is spelled die/eval.

> I can very well investigate this path...

eval deals nicely with die, but not with exit or exec calls.

a> perl -le '$rc = eval{die"foo"};if($@){print$@}else{print$rc}'
foo at -e line 1.

a> perl -le '$rc = eval{exec q(/bin/date)};if($@){print$@}else{print
$rc}'
Sun Feb 21 19:21:49 GMTST 2010
a> perl -le '$rc = eval{exit 25};if($@){print$@}else{print$rc}'
a> echo $?
25

Do I miss something?

Marc

Marc Girod

unread,
Feb 21, 2010, 3:47:34 PM2/21/10
to
On Feb 21, 7:23 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> Do I miss something?

May I override *::exit and *::exec with a function doing die?
Or may I only override Package local functions?

a> perl -le '*::exit=\$die;$rc = eval{exit 25};if($@){print$@}


else{print$rc}'
a> echo $?
25

a> perl -le '*::exec=\$die;$rc = eval{exec "foo"};if($@){print$@}
else{print$rc}'
0

Marc

Ben Morrow

unread,
Feb 21, 2010, 6:19:19 PM2/21/10
to

Quoth Marc Girod <marc....@gmail.com>:

> Hello,
>
> I am only now back to this old thread of mine,
> and to investigating Uri's suggestion...
>
> On Jan 25, 9:57 am, Marc Girod <marc.gi...@gmail.com> wrote:
> > On Jan 24, 8:35 pm, "Uri Guttman" <u...@StemSystems.com> wrote:
>
> > > but longjump in perl is spelled die/eval.
>
> > I can very well investigate this path...
>
> eval deals nicely with die, but not with exit or exec calls.

A piece of reusable code shouldn't normally call exit or exec (except
after a fork). What is the actual problem you are trying to solve?

Ben

Marc Girod

unread,
Feb 22, 2010, 5:23:43 AM2/22/10
to
On Feb 21, 11:19 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> A piece of reusable code shouldn't normally call exit or exec (except
> after a fork). What is the actual problem you are trying to solve?

I am trying to reuse a piece of code which has not been
designed to be reused in that way.
It is a wrapper around a proprietary tool, giving
command line access to a database.
The original tool is mostly used to run one-shot
commands, but it also has a mode in which it stays up
and reads commands in a loop. This mode is convenient
to start the tool in the background, and feed it with
multiple commands.
This comes handy to the kind of enhancements I want to
implement in my own wrapper, which need to perform
numerous database accesses, and gain in performance by
not having to initialize and finalize the tool for
each of them.

Now, I write my wrapper using a framework designed for
this purpose, but not supporting the 'shell' function
described above. So wrappers written so far using this
framework have been emulating the tool in one-shot
commands, but not in the ability to install itself in
the background.

I wish my wrapper to overcome this limitation.

Now, the frustration in describing what intentions
comes from the tool being proprietary, which results
in the fact that I assume you (perl gurus) could not
in general run the code examples I could give.

The database is IBM Rational ClearCase.
The CLI tool is cleartool.
The CPAN perl package giving access to cleartool is
ClearCase::Argv (itself using Argv, and IPC::Open3
among others).
The CPAN wrapper infrastructure is ClearCase::Wrapper.
My own CPAN wrapper is ClearCase::Wrapper::MGi.

The changes I try to implement are for
ClearCase::Wrapper to support the latter, and would
go more specifically to cleartool.plx.

Does this help you to consider my questions?

Thanks,
Marc

Marc Girod

unread,
Feb 24, 2010, 5:07:50 AM2/24/10
to
On Feb 21, 8:47 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> May I override *::exit and *::exec with a function doing die?

Maybe a typo of mine didn't help:

release> perl -le '*::exit=\die;$rc = eval{exit "foo"};if($@){print$@}
else{print$rc}'
Died at -e line 1.
release> perl -le '*::exec=\die;$rc = eval{exec "foo"};if($@){print$@}
else{print$rc}'
Died at -e line 1.

So, at least these work.
Now, I can see that it may not be a good idea to redefine such globale
functions.
E.g. for the case when some other package below would also attempt to
redefine them (not a better idea, probably, and without much brighter
perspectives).

I can check that this work as well:

release> perl -le 'package Foo; *Foo::exit=\die;$rc = eval{exit


"foo"};if($@){print$@}else{print$rc}'

Died at -e line 1.

So, I got the answer to my own questions.
I'll try to make better ones next time.
Thanks,
Marc

Ben Morrow

unread,
Feb 24, 2010, 8:44:13 AM2/24/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 21, 8:47�pm, Marc Girod <marc.gi...@gmail.com> wrote:
>
> > May I override *::exit and *::exec with a function doing die?
>
> Maybe a typo of mine didn't help:
>
> release> perl -le '*::exit=\die;$rc = eval{exit "foo"};if($@){print$@}
> else{print$rc}'
> Died at -e line 1.

Err... no. You can't take a ref to a builtin. The \die expression just
calls die then and there. Also, you can only override a builtin from
within a different package, and the override must happen at compile
time.

BEGIN { package Foo; *main::exit = sub { die } }

> So, at least these work.
> Now, I can see that it may not be a good idea to redefine such globale
> functions.
> E.g. for the case when some other package below would also attempt to
> redefine them (not a better idea, probably, and without much brighter
> perspectives).

Note that an override for &main::exit only applies to code compiled in
package main. Other code will still see CORE::exit.

Ben

Marc Girod

unread,
Feb 25, 2010, 1:04:00 PM2/25/10
to
On Feb 24, 1:44 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> Err... no. You can't take a ref to a builtin. The \die expression just
> calls die then and there. Also, you can only override a builtin from
> within a different package, and the override must happen at compile
> time.
>
>     BEGIN { package Foo; *main::exit = sub { die } }

Thanks...
For both remarks. I guess I would soon have noticed the first, but I
didn't yet.

> Note that an override for &main::exit only applies to code compiled in
> package main. Other code will still see CORE::exit.

But it may be inherited?

Marc

Ben Morrow

unread,
Feb 25, 2010, 3:12:27 PM2/25/10
to

Quoth Marc Girod <marc....@gmail.com>:

No... not unless you call ->exit as a method on a subclass. The
builtin-override logic just looks in the current package, and
CORE::GLOBAL::.

Ben

Marc Girod

unread,
Feb 27, 2010, 1:44:30 PM2/27/10
to
On Feb 25, 8:12 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> No... not unless you call ->exit as a method on a subclass. The
> builtin-override logic just looks in the current package, and
> CORE::GLOBAL::.

OK... Week-end, so I am back to my home work.
I set in the ClearCase::Argv.pm package (among
others...):

BEGIN {
if ($ENV{CLEARTOOL_PLX_LOOP}) {
package ClearCase::Argv;
*main::exit = sub { die @_, "\n" };
*main::exec = sub { die system(@_), "\n" };
}
}

This package does an 'exit' as part of its own
implementation of an 'exec' member.
I hope this 'ClearCase::Argv::exec' would not
collide with the 'main::exec' which we are
overriding here?

Well, I get errors:

BEGIN not safe after errors--compilation aborted at /usr/lib/
perl5/5.10/Carp/Heavy.pm line 11.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
Attempt to reload Carp/Heavy.pm aborted.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
Attempt to reload Carp/Heavy.pm aborted.
...

I read perldebug and set PERLDB_OPTS=AutoTrace
prior to starting my debug session.
This gives among the (long) output an indication
that the errors relate indeed to my change:

...
ClearCase::Argv::CODE(0x1f267b8)(/usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm:19):
19: if ($ENV{CLEARTOOL_PLX_LOOP}) {
20: package ClearCase::Argv;
ClearCase::Argv::CODE(0x1f267b8)(/usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm:21):
21: *main::exit = sub { die @_, "\n" };
Attempt to reload Carp/Heavy.pm aborted.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
ClearCase::Argv::CODE(0x1f267b8)(/usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm:22):
22: *main::exec = sub { die system(@_), "\n" };
Attempt to reload Carp/Heavy.pm aborted.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
ClearCase::Argv::CODE(0x1f1b150)(/usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm:26):
...

And I am lost again...

Marc

P.S. Why must I specify the package in the BEGIN block?
Or must I? On my command line test, it does seem so...

Marc Girod

unread,
Feb 27, 2010, 1:56:22 PM2/27/10
to
On Feb 27, 6:44 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> Well, I get errors:

That is... without the debugger, the errors I get are:

$ perl -Mblib blib/script/cleartool.plx des -s foo
Subroutine main::exit redefined at /usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm line 21.
Subroutine main::exec redefined at /usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm line 22.
Name "DB::single" used only once: possible typo at blib/script/
cleartool.plx line 9, <GEN1> line 16.
foo

Let's say that 'foo' is the expected output.
Only, it is here followed with a standard exit,
so that no following input is read with:

$ cat <<eot | perl -Mblib blib/script/cleartool.plx
des -s foo
des -s bar

Marc

Marc Girod

unread,
Feb 27, 2010, 2:33:02 PM2/27/10
to
On Feb 27, 6:56 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> That is... without the debugger, the errors I get are:

And under the debugger, in my AutoTrace output,
the first error is:

ClearCase::Wrapper::CODE(0x1ae0ab8)(/cygdrive/o/atcctest/ClearCase-
Wrapper/blib/lib/ClearCase/Wrapper.pm:119):
119: next unless eval "exists \&$tglob";


BEGIN not safe after errors--compilation aborted at /usr/lib/
perl5/5.10/Carp/Heavy.pm line 11.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
Attempt to reload Carp/Heavy.pm aborted.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.

This is a place in the ClearCase::Wrapper.pm code,
where it examines out of the AutoSplit modules
produced from Wrapper functions, which ones
correspond to 'commands' of the tool being
emulated:

# Now the overlay module is read in. We need to examine its
# newly-created symbol table, determine which functions
# it defined, and import them here. The same basic thing is
# done for the base package later.
my %names = %{"${pkg}::"};
for (keys %names) {
my $tglob = "${pkg}::$_";
# Skip functions that can't be names of valid cleartool ops.
next if m%^_?[A-Z]%;
# Skip typeglobs that don't involve functions. We can only
# do this test under >=5.6.0 since exists() on a coderef
# is a new feature. The eval is needed to avoid a compile-
# time error in <5.6.0.
if ($] >= 5.006) {
next unless eval "exists \&$tglob";
}

The AutoTrace transcript shows earlier 'require Carp;'
but for some reason, doesn't trace its loading,
contrarily to blib, Cwd, strict, Exporter, etc...

This only shows that I don't understand what gets traced.

Marc

Marc Girod

unread,
Feb 27, 2010, 2:48:55 PM2/27/10
to
On Feb 27, 7:33 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> ClearCase::Wrapper::CODE(0x1ae0ab8)(/cygdrive/o/atcctest/ClearCase-
> Wrapper/blib/lib/ClearCase/Wrapper.pm:119):
> 119:                        next unless eval "exists \&$tglob";

Oh! Now I understood how '$DB::single = 1' works!
So, I could 'put a breakpoint' there.

DB<1> x %names
0 '__ANON__[/usr/lib/perl5/site_perl/5.10/ClearCase/Wrapper/DSB.pm:
13]'
1 *ClearCase::Wrapper::DSB::__ANON__[/usr/lib/perl5/site_perl/5.10/
ClearCase/Wrapper/DSB.pm:13]
2 'lock'
3 *ClearCase::Wrapper::DSB::lock
...
68 'update'
69 *ClearCase::Wrapper::DSB::update
ClearCase::Wrapper::CODE(0x1960c08)(/cygdrive/o/atcctest/ClearCase-
Wrapper/blib/lib/ClearCase/Wrapper.pm:120):
120: next unless eval "exists \&$tglob";
DB<2> p $_
__ANON__[/usr/lib/perl5/site_perl/5.10/ClearCase/Wrapper/DSB.pm:13]
DB<3> s


BEGIN not safe after errors--compilation aborted at /usr/lib/
perl5/5.10/Carp/Heavy.pm line 11.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.
Attempt to reload Carp/Heavy.pm aborted.
Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.

...

I hope I don't bore you...
Marc

Marc Girod

unread,
Feb 27, 2010, 3:22:18 PM2/27/10
to
On Feb 27, 7:48 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> > 119:                        next unless eval "exists \&$tglob";

It would seem that this problem vanishes
(and leaves place to the original one) if
I change the syntax into either of:

next unless exists &{$tglob};
next unless eval { exists &{$tglob} };

Again I am not quite sure I am not also
changing the semantics... but under the
debugger, it looks like doing what I
understood was intended.

But as I said, I am only back to:

ClearCase-Wrapper> perl -Mblib blib/script/cleartool.plx des -s foo


Subroutine main::exit redefined at /usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm line 21.
Subroutine main::exec redefined at /usr/lib/perl5/site_perl/5.10/
ClearCase/Argv.pm line 22.

foo

Marc

Ben Morrow

unread,
Feb 27, 2010, 4:06:07 PM2/27/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 25, 8:12�pm, Ben Morrow <b...@morrow.me.uk> wrote:
>
> > No... not unless you call ->exit as a method on a subclass. The
> > builtin-override logic just looks in the current package, and
> > CORE::GLOBAL::.
>
> OK... Week-end, so I am back to my home work.
> I set in the ClearCase::Argv.pm package (among
> others...):
>
> BEGIN {
> if ($ENV{CLEARTOOL_PLX_LOOP}) {
> package ClearCase::Argv;
> *main::exit = sub { die @_, "\n" };
> *main::exec = sub { die system(@_), "\n" };
> }
> }

I don't understand what you are trying to acheive here. What the code
above will actually do is: any code compiled in package 'main' after the
BEGIN block runs, that calls 'exit' or 'exec', will call your custom
subs instead. Is that what you meant? (Exporting into a specific package
like that is usually a very mad idea. What if your caller isn't main::
but some other package?)

> This package does an 'exit' as part of its own
> implementation of an 'exec' member.
> I hope this 'ClearCase::Argv::exec' would not
> collide with the 'main::exec' which we are
> overriding here?

When you say 'member' you mean 'method', or perhaps 'function'? Method
calls to ClearCase::Argv->exec won't be affected. Calls to 'exit' or
'exec' from within the ClearCase::Argv package won't be affected, they
will call the builtin as usual.

> P.S. Why must I specify the package in the BEGIN block?
> Or must I? On my command line test, it does seem so...

Overrides of builtins must be imported while in another package, in an
attempt to stop you doing it accidentally. That is,

package Foo;
*main::exec = sub {...};

will be recognized as an override while in package main, but

package main;
*exec = sub {...};

won't. Since I presume your module starts with

package ClearCase::Argv;

you shouldn't need another package statement inside the BEGIN block.

Ben

Ben Morrow

unread,
Feb 27, 2010, 4:07:56 PM2/27/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 27, 6:44�pm, Marc Girod <marc.gi...@gmail.com> wrote:
>
> > Well, I get errors:
>
> That is... without the debugger, the errors I get are:
>
> $ perl -Mblib blib/script/cleartool.plx des -s foo
> Subroutine main::exit redefined at /usr/lib/perl5/site_perl/5.10/
> ClearCase/Argv.pm line 21.
> Subroutine main::exec redefined at /usr/lib/perl5/site_perl/5.10/
> ClearCase/Argv.pm line 22.
> Name "DB::single" used only once: possible typo at blib/script/
> cleartool.plx line 9, <GEN1> line 16.

These are not errors, they are warnings. They appear to be fairly
self-explanatory...

> foo
>
> Let's say that 'foo' is the expected output.
> Only, it is here followed with a standard exit,
> so that no following input is read with:
>
> $ cat <<eot | perl -Mblib blib/script/cleartool.plx
> des -s foo
> des -s bar

That is a separate issue from the warnings, and since I haven't seen
the code I have no idea as to the cause.

Ben

Marc Girod

unread,
Feb 27, 2010, 5:14:39 PM2/27/10
to
On Feb 27, 9:06 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> I don't understand what you are trying to achieve here. What the code


> above will actually do is: any code compiled in package 'main' after the
> BEGIN block runs, that calls 'exit' or 'exec', will call your custom
> subs instead. Is that what you meant?

I have no package explicitely named 'main',
so obviously I have misunderstood something
you wrote earlier.
Now, this makes indeed the 'redefine' errors
'self-explanatory' as you say.
Or... maybe not quite. I understood I was
redefining the meaning of a global 'exec'
in different package contexts.

> (Exporting into a specific package
> like that is usually a very mad idea.
> What if your caller isn't main::
> but some other package?)

Sorry, but what is 'main'? Is there a main?
In C, there is a 'main' symbol. It is
garanteed to be unique, in the context of
every program. This is what I understood.

In fact, I would still believe this is OK.
So, it is now that I must be misunderstanding
you...
At least I don't get errors mentioning
'*main::'...

I am writing a wrapper for a command line
tool, so my caller will be 'main'...
The caller is the 'cleartool.plx' script.

> When you say 'member' you mean 'method', or perhaps 'function'? Method
> calls to ClearCase::Argv->exec won't be affected. Calls to 'exit' or
> 'exec' from within the ClearCase::Argv package won't be affected, they
> will call the builtin as usual.

'Method' is the word Smalltalk used.
'Member' (function) is the word for C++.
'Function' is the C word for something
slightly different (but called 'procedure'
in Fortran). OK, there are functions in Lisp
as well, and there are significant
differences... The terminology is very
confusing. By member, I mean a function
in the restricted namespace of a class
(aka package). In addition, I assume that it
takes a first (syntactically implicit)
argument being a reference to an instance
of the class. This aspect is irrelevant here.

> Overrides of builtins must be imported while in another package, in an
> attempt to stop you doing it accidentally. That is,
>
>     package Foo;
>     *main::exec = sub {...};
>
> will be recognized as an override while in package main, but
>
>     package main;
>     *exec = sub {...};
>
> won't. Since I presume your module starts with
>
>     package ClearCase::Argv;
>
> you shouldn't need another package statement inside the BEGIN block.

I have:
- a toplevl script: cleartool.plx (the wrapper)
- a ClearCase::Wrapper module, which does
define some functions, and use exit and exec
in ways I want to override
- a ClearCase::Argv module, which is used to
implement the functions, and offers one 'exec'
among other, which itself uses exit, in a way
which I want to override
- two specialized wrapper modules:
- ClearCase::Wrapper::DSB which defines more
functions (among which the 'des' which I use
in my tests), and does use exit and exec in
ways I want to override.
- ClearCase::Wrapper::MGI of which I am the
author, and thus does *not* use exit nor
exec .
These two modules are 'discovered' dynamically
and loaded by ClearCase::Wrapper.
There could in theory be more of them.

So, my understanding is that I must override
exec and exit in at least 3 packages:
ClearCase::Argv
ClearCase::Wrapper
ClearCase::Wrapper::DSB

(and probably in a 4th one: Argv, which is used
by ClearCase::Argv).

Where do I do this, and how do I prefix the
2 names?
So far, I thought the functions I was overriding
were global main:: functions, and I had to do it
*in* every package.
Obviously, this was wrong...

Thanks
Marc

Marc Girod

unread,
Feb 27, 2010, 5:39:35 PM2/27/10
to
On Feb 27, 9:07 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> These are not errors, they are warnings.

OK.

> They appear to be fairly self-explanatory...

Apart for the fact that in the end, the
behaviour of exit is still the original one...
So that I don't understand what was overridden.
Not what I intended...

> That is a separate issue from the warnings, and since I haven't seen
> the code I have no idea as to the cause.

*The* code?
If I check it in my Google site, will you read
it (given that you won't be able to run it as
previously explained)?

The previous version is of course already there.
It is only a matter of pushing new increments...

The site is:

http://code.google.com/p/clearcase-cpan/source/browse/#svn/branches

OK... DSB is not there yet, and even if the
changes to the versions there are small,
they are just what I am asking about.

But let's say that within cleartool.plx,
there is a 'one_cmd' function, and the
new code there looks like this:

my $rc = eval { $cmd->(@ARGV) };
if ($@) {
chomp $@;
$rc = $@;
} else {
warn "Normal return: $rc";
}
# ... and exit unless it returned zero.
return $rc;

And there is a loop a bit later such as:

my $rc;
require Text::ParseWords;
while (my $line = <>) {
chomp $line;
last if $line eq 'quit';
local @ARGV = Text::ParseWords::shellwords($line);
$rc = one_cmd;
}
exit $rc;

The problem so far being that in the case of 'des',
$cmd->(@ARGV) never returns or dies: it just exits.

I am sorry: I kind of believe you won't want to dig
into this in that way either.
This is a top-down way, and I believe it is not
the right way to communicate. It is the way to
avoid communications.
I believe we should be able to drive this bottom-up
which requires communications: that we understand
what prevents each other from understanding.

I don't say it is easy. I just believe it is the
only scalable way, because it depends on 'local'
complexity.

Thanks in any case,
Marc

Ben Morrow

unread,
Feb 27, 2010, 5:58:20 PM2/27/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 27, 9:06�pm, Ben Morrow <b...@morrow.me.uk> wrote:
>
> > I don't understand what you are trying to achieve here. What the code
> > above will actually do is: any code compiled in package 'main' after the
> > BEGIN block runs, that calls 'exit' or 'exec', will call your custom
> > subs instead. Is that what you meant?
>
> I have no package explicitely named 'main',
> so obviously I have misunderstood something
> you wrote earlier.

Perl starts in package 'main', so any code that comes before a 'package'
statement is compiled in package main. I think you perlhaps need to
review perlmod.

> Now, this makes indeed the 'redefine' errors
> 'self-explanatory' as you say.
> Or... maybe not quite. I understood I was
> redefining the meaning of a global 'exec'
> in different package contexts.

Hmmm. Not quite. A statement like

exec "one", "two";

is usually compiled as a builtin. However, if there is a sub in the
current package called 'exec', *and* that sub was exported into the
current package by a different package, then it is compiled as a call to
that sub instead.

> > (Exporting into a specific package
> > like that is usually a very mad idea.
> > What if your caller isn't main::
> > but some other package?)
>
> Sorry, but what is 'main'? Is there a main?
> In C, there is a 'main' symbol. It is
> garanteed to be unique, in the context of
> every program. This is what I understood.

No, not at all. 'main' is just the name of the default package. See
above.

> In fact, I would still believe this is OK.
> So, it is now that I must be misunderstanding
> you...
> At least I don't get errors mentioning
> '*main::'...
>
> I am writing a wrapper for a command line
> tool, so my caller will be 'main'...
> The caller is the 'cleartool.plx' script.

OK, but since you are writing this as a module you must be at least
implicitly assuming it might be used elsewhere. The usual method is to
use 'caller' in your package's 'import' method, which will tell you
which package the 'use' statement happed from:

package ClearCase::Argv;

sub import {
my $pkg = caller;
{
no strict 'refs';
*{"$pkg\::exec"} = sub { ... };
}
# whatever else you need to do
# if you want Exporter to work you can
goto &Exporter::import;
}

Since it appears you are working 'backwards', and trying to change the
behaviour of modules that aren't loaded yet, you need to explicitly
export into ClearCase::Wrapper &c.

> > When you say 'member' you mean 'method', or perhaps 'function'? Method
> > calls to ClearCase::Argv->exec won't be affected. Calls to 'exit' or
> > 'exec' from within the ClearCase::Argv package won't be affected, they
> > will call the builtin as usual.
>
> 'Method' is the word Smalltalk used.
> 'Member' (function) is the word for C++.
> 'Function' is the C word for something
> slightly different (but called 'procedure'
> in Fortran). OK, there are functions in Lisp
> as well, and there are significant
> differences... The terminology is very
> confusing. By member, I mean a function
> in the restricted namespace of a class
> (aka package). In addition, I assume that it
> takes a first (syntactically implicit)
> argument being a reference to an instance
> of the class. This aspect is irrelevant here.

OK. 'Member' is not usually used in that sense in Perl. A function call
(or sub call) looks like

foo(1, 2, 3);

or

Some::Package::foo(1, 2, 3);

The first form will look for a builtin with that name, or a 'sub foo' in
the current package. The second form will always look for a 'sub foo' in
Some::Package. A method call looks like

Some::Package->foo(1, 2);
$obj->foo(1, 2);

and will look for a 'sub foo' in Some::Package or anything it inherits
from, and call it with an implicit first argument. Method calls never
compile as builtins, so you can have a method called 'exec' with no
problems.

> > Overrides of builtins must be imported while in another package, in an
> > attempt to stop you doing it accidentally. That is,
> >
> > � � package Foo;
> > � � *main::exec = sub {...};
> >
> > will be recognized as an override while in package main, but
> >
> > � � package main;
> > � � *exec = sub {...};
> >
> > won't. Since I presume your module starts with
> >
> > � � package ClearCase::Argv;
> >
> > you shouldn't need another package statement inside the BEGIN block.
>
> I have:
> - a toplevl script: cleartool.plx (the wrapper)
> - a ClearCase::Wrapper module, which does
> define some functions, and use exit and exec
> in ways I want to override
> - a ClearCase::Argv module, which is used to
> implement the functions, and offers one 'exec'
> among other, which itself uses exit, in a way
> which I want to override

Is this 'exec' called as a method or a function? If it's called as a
method, or if it's always called fully-qualified, you can simply ignore
the fact it's called 'exec'.

> - two specialized wrapper modules:
> - ClearCase::Wrapper::DSB which defines more
> functions (among which the 'des' which I use
> in my tests), and does use exit and exec in
> ways I want to override.
> - ClearCase::Wrapper::MGI of which I am the
> author, and thus does *not* use exit nor
> exec .
> These two modules are 'discovered' dynamically
> and loaded by ClearCase::Wrapper.

If you wish to override CC::W's use of 'exec', this must happen *before*
CC::W is loaded. This probably means you need to switch to using a
module MGI::ClearCase, which does the overrides and *then* loads
ClearCase::Wrapper, and avoid loading CC::W in cleartool.plx.

> There could in theory be more of them.
>
> So, my understanding is that I must override
> exec and exit in at least 3 packages:
> ClearCase::Argv
> ClearCase::Wrapper
> ClearCase::Wrapper::DSB
>
> (and probably in a 4th one: Argv, which is used
> by ClearCase::Argv).
>
> Where do I do this, and how do I prefix the
> 2 names?

I would say you want something like this:

package MGI::ClearCase;

use warnings;
use strict;

my $exec = sub {...};
my $exit = sub {...};

*ClearCase::Wrapper::exec = $exec;
*ClearCase::Wrapper::exit = $exit;
# leave CC::A::exec, since it's already being redefined
*ClearCase::Argv::exit = $exit;
*ClearCase::Wrapper::DSB::exec = $exec;
*ClearCase::Wrapper::DSB::exit = $exit;

# 'require' not 'use', so it isn't loaded until after the overrides
require ClearCase::Wrapper;

# more stuff

1;

You shouldn't get any 'redefined' warnings from this; if you do, it
indicates a problem.

> So far, I thought the functions I was overriding
> were global main:: functions, and I had to do it
> *in* every package.
> Obviously, this was wrong...

No, they aren't functions (that is, Perl subs) at all, they're builtins.
They are recognised specially by the compiler, and compiled into special
ops, *unless* they have been overridden at that point.

Ben

Ilya Zakharevich

unread,
Feb 27, 2010, 6:22:23 PM2/27/10
to
On 2010-02-27, Marc Girod <marc....@gmail.com> wrote:
> BEGIN {
> if ($ENV{CLEARTOOL_PLX_LOOP}) {
> package ClearCase::Argv;
> *main::exit = sub { die @_, "\n" };
> *main::exec = sub { die system(@_), "\n" };
> }
> }

> Compilation failed in require at /usr/lib/perl5/5.10/Carp.pm line 33.


> Attempt to reload Carp/Heavy.pm aborted.

(At least with older versions of Perl) this means that a warning/error
is generated when "sitting deep in some tricky compilataion phase".
(So your module is not loaded in some "normal way".)
Just induce a harmless warning before loading your module, and/or load
your module early.

Hope this helps,
Ilya

Marc Girod

unread,
Feb 27, 2010, 6:30:08 PM2/27/10
to
On Feb 27, 10:58 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> Perl starts in package 'main', so any code that comes before a 'package'
> statement is compiled in package main. I think you perlhaps need to
> review perlmod.

Quite possible indeed. I'll do it.

> Hmmm. Not quite. A statement like
>
>     exec "one", "two";
>
> is usually compiled as a builtin. However, if there is a sub in the
> current package called 'exec', *and* that sub was exported into the
> current package by a different package, then it is compiled as a call to
> that sub instead.

OK... The clause *and* is still not quite clear to me,
but I'll try to work on it.

> No, not at all. 'main' is just the name of the default package. See
> above.

OK.

> OK, but since you are writing this as a module you must be at least
> implicitly assuming it might be used elsewhere. The usual method is to
> use 'caller' in your package's 'import' method, which will tell you
> which package the 'use' statement happed from:

The module is there... I believe in order to autoload
the split code... i.e. for performance reasons.
I don't see an other reason for now.
I cannot really see that it would be 'used'.
This is why it does exec and exit...

>     package ClearCase::Argv;
>
>     sub import {
>         my $pkg = caller;
>         {
>             no strict 'refs';
>             *{"$pkg\::exec"} = sub { ... };
>         }
>         # whatever else you need to do
>         # if you want Exporter to work you can
>         goto &Exporter::import;
>     }
>
> Since it appears you are working 'backwards', and trying to change the
> behaviour of modules that aren't loaded yet, you need to explicitly
> export into ClearCase::Wrapper &c.

> OK. 'Member' is not usually used in that sense in Perl.

OK. I can just see that all my references only
confuse me.

> A function call (or sub call) looks like
>
>     foo(1, 2, 3);
>
> or
>
>     Some::Package::foo(1, 2, 3);
>
> The first form will look for a builtin with that name, or a 'sub foo' in
> the current package. The second form will always look for a 'sub foo' in
> Some::Package. A method call looks like
>
>     Some::Package->foo(1, 2);
>     $obj->foo(1, 2);
>
> and will look for a 'sub foo' in Some::Package or anything it inherits
> from, and call it with an implicit first argument. Method calls never
> compile as builtins, so you can have a method called 'exec' with no
> problems.

But it is 'defined' in the same way...

sub exec {...}

whether is is intended as a function or a method?
Something I have to grasp there...

> Is this 'exec' called as a method or a function? If it's called as a
> method, or if it's always called fully-qualified, you can simply ignore
> the fact it's called 'exec'.

Well, I now looked that indeed, it is always called
as a method. Which explains, as you said, that there
is no problem.

> If you wish to override CC::W's use of 'exec', this must happen *before*
> CC::W is loaded. This probably means you need to switch to using a
> module MGI::ClearCase, which does the overrides and *then* loads
> ClearCase::Wrapper, and avoid loading CC::W in cleartool.plx.

OK...

> I would say you want something like this:
>
>     package MGI::ClearCase;
>
>     use warnings;
>     use strict;
>
>     my $exec = sub {...};
>     my $exit = sub {...};
>
>     *ClearCase::Wrapper::exec       = $exec;
>     *ClearCase::Wrapper::exit       = $exit;
>     # leave CC::A::exec, since it's already being redefined
>     *ClearCase::Argv::exit          = $exit;
>     *ClearCase::Wrapper::DSB::exec  = $exec;
>     *ClearCase::Wrapper::DSB::exit  = $exit;
>
>     # 'require' not 'use', so it isn't loaded until after the overrides
>     require ClearCase::Wrapper;
>
>     # more stuff
>
>     1;

Because of the require, you don't need a BEGIN block?
With a BEGIN block, I can 'use' the module?

> You shouldn't get any 'redefined' warnings from this; if you do, it
> indicates a problem.

> No, they aren't functions (that is, Perl subs) at all, they're builtins.

OK. builtins are not functions!
Terminology again...

> They are recognised specially by the compiler, and compiled into special
> ops, *unless* they have been overridden at that point.

OK.

Now, I committed (produced) this:

Foo> cat foo
#!/usr/bin/perl -w

use strict;
BEGIN {
package Bar;
*Foo::exit = sub { die 'Died ', @_, "\n" }
}
use Foo;

my $foo = new Foo;
$foo->foo;
print "foo end\n";
exit 0;
Foo> perl -I. foo; echo $?
Foo:foo
Died 85
255

It looks already close...
Thanks a lot for your patience!

Marc

Ben Morrow

unread,
Feb 27, 2010, 7:18:50 PM2/27/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 27, 10:58�pm, Ben Morrow <b...@morrow.me.uk> wrote:
>
> > Hmmm. Not quite. A statement like
> >
> > � � exec "one", "two";
> >
> > is usually compiled as a builtin. However, if there is a sub in the
> > current package called 'exec', *and* that sub was exported into the
> > current package by a different package, then it is compiled as a call to
> > that sub instead.
>
> OK... The clause *and* is still not quite clear to me,
> but I'll try to work on it.

It is confusing. Really the only way to understand it is to play with
the different possibilities until you see what works and what doesn't.

> > A function call (or sub call) looks like
> >
> > � � foo(1, 2, 3);
> >
> > or
> >
> > � � Some::Package::foo(1, 2, 3);
> >
> > The first form will look for a builtin with that name, or a 'sub foo' in
> > the current package. The second form will always look for a 'sub foo' in
> > Some::Package. A method call looks like
> >
> > � � Some::Package->foo(1, 2);
> > � � $obj->foo(1, 2);
> >
> > and will look for a 'sub foo' in Some::Package or anything it inherits
> > from, and call it with an implicit first argument. Method calls never
> > compile as builtins, so you can have a method called 'exec' with no
> > problems.
>
> But it is 'defined' in the same way...
>
> sub exec {...}
>
> whether is is intended as a function or a method?
> Something I have to grasp there...

Yes. This is also a little confusing, and occasionally somewhat annoying
:).

> > I would say you want something like this:
> >
> > � � package MGI::ClearCase;
> >
> > � � use warnings;
> > � � use strict;
> >
> > � � my $exec = sub {...};
> > � � my $exit = sub {...};
> >
> > � � *ClearCase::Wrapper::exec � � � = $exec;
> > � � *ClearCase::Wrapper::exit � � � = $exit;
> > � � # leave CC::A::exec, since it's already being redefined
> > � � *ClearCase::Argv::exit � � � � �= $exit;
> > � � *ClearCase::Wrapper::DSB::exec �= $exec;
> > � � *ClearCase::Wrapper::DSB::exit �= $exit;
> >
> > � � # 'require' not 'use', so it isn't loaded until after the overrides
> > � � require ClearCase::Wrapper;
> >
> > � � # more stuff
> >
> > � � 1;
>
> Because of the require, you don't need a BEGIN block?
> With a BEGIN block, I can 'use' the module?

Yes to both.

> > No, they aren't functions (that is, Perl subs) at all, they're builtins.
>
> OK. builtins are not functions!
> Terminology again...

Despite being documented in perlfunc... :). Actually, 'function' is used
somewhat ambiguously in Perl. It's often used to mean 'a Perl sub or a
builtin', while here I was using it to mean 'something called as a
function rather than a method'. What's important is to realise that the
builtins are fundamentally different from the things you define with
'sub', and they are (intentionally) a lot harder to redefine.

Ben

Ben Morrow

unread,
Feb 27, 2010, 7:04:07 PM2/27/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 27, 9:07�pm, Ben Morrow <b...@morrow.me.uk> wrote:
>
> > These are not errors, they are warnings.
>
> OK.
>
> > They appear to be fairly self-explanatory...
>
> Apart for the fact that in the end, the
> behaviour of exit is still the original one...
> So that I don't understand what was overridden.
> Not what I intended...

You have defined the sub main::exit in two places. You have only
mentioned the variable $DB::single in one place. (Neither of these has
anything to do with exit not getting overridden.)

> > That is a separate issue from the warnings, and since I haven't seen
> > the code I have no idea as to the cause.
>
> *The* code?
> If I check it in my Google site, will you read
> it (given that you won't be able to run it as
> previously explained)?

No. However, if you cut out *everything* *possible* that doesn't make
the problem go away, including any third-party modules or external
binaries, and post the result, I might look at it. (If it's too long to
post there's almost certainly more you can cut out.) OTOH, you might
work it out yourself, or at least get down to a piece of code with only
*one* bug, which would be a start. This *will* be a lot of work, but
there's really no way around that.

> But let's say that within cleartool.plx,
> there is a 'one_cmd' function, and the
> new code there looks like this:
>
> my $rc = eval { $cmd->(@ARGV) };

Given the code below, you appear to be using $cmd as a symref. Don't do
that, use a hash of subrefs instead. If you are using 'strict' this will
always throw a 'Can't use string as a subroutine ref' error, which may
be the root of your problem. (Your problem in *this* bit of code, at any
rate. It has nothing to do with your problem overriding 'exit', which is
why you should take it out until you've solved that problem.)

You are also passing parameters to one_cmd in the global @ARGV variable.
Don't do that, pass an arrayref of arguments instead.

> if ($@) {
> chomp $@;
> $rc = $@;
> } else {
> warn "Normal return: $rc";
> }
> # ... and exit unless it returned zero.
> return $rc;
>
> And there is a loop a bit later such as:
>
> my $rc;
> require Text::ParseWords;
> while (my $line = <>) {
> chomp $line;
> last if $line eq 'quit';
> local @ARGV = Text::ParseWords::shellwords($line);
> $rc = one_cmd;
> }
> exit $rc;
>
> The problem so far being that in the case of 'des',
> $cmd->(@ARGV) never returns or dies: it just exits.

How do you know? I think the eval {} fails, with $@ = "Can't use...",
one_cmd returns, and the code above exits.

> I am sorry: I kind of believe you won't want to dig
> into this in that way either.
> This is a top-down way, and I believe it is not
> the right way to communicate. It is the way to
> avoid communications.
> I believe we should be able to drive this bottom-up
> which requires communications: that we understand
> what prevents each other from understanding.

I can't see what you are or are not understanding unless I see your
code. This doesn't mean I need to see the whole program, just some piece
of code you've written that you think ought to work, but doesn't.

> I don't say it is easy. I just believe it is the
> only scalable way, because it depends on 'local'
> complexity.

That is correct; but reducing the complexity of the problem is *your*
job, not mine.

Ben

Marc Girod

unread,
Feb 28, 2010, 5:20:41 AM2/28/10
to
On Feb 27, 11:22 pm, Ilya Zakharevich <nospam-ab...@ilyaz.org> wrote:

> Hope this helps,

Thanks... Yes, it helps, at least not to bother too much,
especially now that it disappeared.

Marc

Marc Girod

unread,
Feb 28, 2010, 5:32:29 AM2/28/10
to
On Feb 28, 12:04 am, Ben Morrow <b...@morrow.me.uk> wrote:

> That is correct; but reducing the complexity of the problem is *your*
> job, not mine.

Well, we managed more or less.
I got something to work now: thanks a lot!
I still have to clean it somewhat.

A few notes:
- @ARGV: I don't think I can change that. It is too
deep in the code I want to reuse, without changing
it; and not without reasons and advantages, in
terms of preserving the context of use of the
tool being emulated. This allows to switch back
and forth, e.g. for debugging purposes.
- How did I know: because I debugged it.
- $cmd: I am again walking from somewhere... I don't
clearly see the gain in suggesting to the original
author a change there...
- main::exit redefinition: I got it now, thanks to you

So, big thanks again.
I have an other question (and others coming for sure)
but it is for an other thread!
Marc

Marc Girod

unread,
Feb 28, 2010, 7:39:43 AM2/28/10
to
On Feb 28, 10:32 am, Marc Girod <marc.gi...@gmail.com> wrote:

> I have an other question (and others coming for sure)
> but it is for an other thread!

I found the answer to that one, but found another
which is more of a continuation of this thread...

I looked now at the last module I had forgotten
until now: Argv.
This one does define an 'exec' method, in which it
uses the 'exec' builtin.
If I override 'exec' prior to requiring the module,
I do get a warning for the redefinition, i.e. the
definition of the method.
Am I right to believe it is safe for me to ignore
it? The method will get defined, and use my own
overriding instead of the builtin?

It is a bit of a tricky fallback case when this one
would actually be invoked, if ever in the context
of the wrapper (this Argv module is not restricted
to be used for ClearCase...)

Marc

Marc Girod

unread,
Feb 28, 2010, 8:05:39 AM2/28/10
to
On Feb 28, 12:39 pm, Marc Girod <marc.gi...@gmail.com> wrote:

> Am I right to believe it is safe for me to ignore
> it? The method will get defined, and use my own
> overriding instead of the builtin?

I believe I answered my own question:

ClearCase-Wrapper> cat ~/tmp/perl/redef
#!/usr/bin/perl -w

# no warnings qw(redefine);

my $exec = sub { print "my exec\n"; };
package Dummy;
*Foo::exec = $exec;
package Foo;
sub exec { print "Foo::exec: "; exec @_; }
Foo::exec '/bin/date';
print "foo\n";
ClearCase-Wrapper> ~/tmp/perl/redef
Subroutine Foo::exec redefined at /home/emagiro/tmp/perl/redef line 7.
my exec
foo

and I believe the asnwer is 'yes'.

Marc

Ben Morrow

unread,
Feb 28, 2010, 10:20:56 AM2/28/10
to

Quoth Marc Girod <marc....@gmail.com>:

No, you haven't, and no, it isn't :(.

The test is wrong because the 'sub exec' happens before the '*Foo::exec
= $exec'. Since this is all one file, the sub is compiled at compile
time and the assignment happens at run time, so your override gets
called. (Note that the original sub didn't get called, though, so this
still isn't quite what you need.)

However, if you put the assignment in a BEGIN block (as in your real
setup) you will find that the 'sub exec' completely wipes out your
override. The only way around this is to monkey-patch Argv after you
load it, and replace &Argv::exec with a copy of that sub that calls your
wrapper instead of the builtin. That is, you need

BEGIN {
require Argv;
no warnings "redefine";
*Argv::exec = sub {
# here copy the body of 'sub exec' from Argv.pm, but replace
# the two calls to 'exec(@cmd)' with '$exec->(@cmd)'.
};
}

before anything else tries to use Argv.

Ben

Marc Girod

unread,
Feb 28, 2010, 3:50:43 PM2/28/10
to
On Feb 28, 3:20 pm, Ben Morrow <b...@morrow.me.uk> wrote:
> No, you haven't, and no, it isn't :(.

Life is hard and then you die...

> The test is wrong because the 'sub exec' happens before the '*Foo::exec
> = $exec'. Since this is all one file, the sub is compiled at compile
> time and the assignment happens at run time, so your override gets
> called.

OK.

> (Note that the original sub didn't get called, though, so this
> still isn't quite what you need.)

You mean that I should have noticed that the output wasn't:

Foo::exec: my exec
foo

Right?
Well yes. This is not what I wanted.

I can see that, as Foo is a package and not a class,
Foo::exec is a function and not a method, so that
there is a recusion in the code before any override.
So, there is no solution to discriminate the two in
this test. But fortunately, there is in the real
case...

In the meanwhile, I got a similar problem with my
real code, as I overrode my own member data, because
I had named it $exec, so that it matched *exec...

> However, if you put the assignment in a BEGIN block (as in your real
> setup) you will find that the 'sub exec' completely wipes out your
> override.

OK: I get the recursion effect 'back'.

> The only way around this is to monkey-patch Argv after you
> load it, and replace &Argv::exec with a copy of that sub that calls your
> wrapper instead of the builtin. That is, you need

>     BEGIN {
>         require Argv;
>         no warnings "redefine";
>         *Argv::exec = sub {
>             # here copy the body of 'sub exec' from Argv.pm, but replace
>             # the two calls to 'exec(@cmd)' with '$exec->(@cmd)'.
>         };
>     }

> before anything else tries to use Argv.

Argh. This is ugly (no offense).
But I can see that it might indeed be the only way.
I.e. I do not override the builtin at all, but
only the method, right?
I just don't care anymore for the builtin...

And this is only for Argv, for the other cases,
the previous scheme should work?
I have to sleep over this.
Thanks again...

Marc

Ben Morrow

unread,
Feb 28, 2010, 5:34:10 PM2/28/10
to

Quoth Marc Girod <marc....@gmail.com>:

> On Feb 28, 3:20�pm, Ben Morrow <b...@morrow.me.uk> wrote:
>
> In the meanwhile, I got a similar problem with my
> real code, as I overrode my own member data, because
> I had named it $exec, so that it matched *exec...

Since you are (I hope) using 'my' variables, you can limit their scope
with blocks. If you follow a strict policy of limiting variables to the
scope they're actually needed in, you will be much less likely to stomp
on things you didn't mean to.

> > The only way around this is to monkey-patch Argv after you
> > load it, and replace &Argv::exec with a copy of that sub that calls your
> > wrapper instead of the builtin. That is, you need
>
> > � � BEGIN {
> > � � � � require Argv;
> > � � � � no warnings "redefine";
> > � � � � *Argv::exec = sub {
> > � � � � � � # here copy the body of 'sub exec' from Argv.pm, but replace
> > � � � � � � # the two calls to 'exec(@cmd)' with '$exec->(@cmd)'.
> > � � � � };
> > � � }
>
> > before anything else tries to use Argv.
>
> Argh. This is ugly (no offense).
> But I can see that it might indeed be the only way.

It is deeply ugly, not to mention seriously fragile if you upgrade Argv
and anything internal changes. I don't think there's anything else you
can do, though (well, beyond using XS to switch out pp_exec for
something else in PL_ppaddr... actually that's not a stupid idea. I
wonder if there's a CPAN module that will do that for you?).

> I.e. I do not override the builtin at all, but
> only the method, right?
> I just don't care anymore for the builtin...

Yes, that's right.

> And this is only for Argv, for the other cases,
> the previous scheme should work?

Yes.

Ben

Marc Girod

unread,
Mar 1, 2010, 2:14:20 PM3/1/10
to
On Feb 28, 10:34 pm, Ben Morrow <b...@morrow.me.uk> wrote:

> > I.e. I do not override the builtin at all, but
> > only the method, right?
> > I just don't care anymore for the builtin...
>
> Yes, that's right.

Fortunately, in that case, I have an other
solution.
I can redefine:

sub exec {
my $self = shift;
die $self->system(@_);
}

Nobody else uses the naked 'exec' in that scope.

I.e. I am afraid that the current situation:

die system(@_)

even if it does pass the object reference as first
parameter, ends up calling the builtin?

Marc

Ben Morrow

unread,
Mar 1, 2010, 2:27:32 PM3/1/10
to

Quoth Marc Girod <marc....@gmail.com>:

*Yes*. A function call that just happens to pass a reference is quite
different from a method call.

Ben

0 new messages