develooper Front page | perl.perl5.porters | Postings from February 2009

method names clash by importing

Thread Next
From:
Dmitry Karasik
Date:
February 13, 2009 16:22
Subject:
method names clash by importing
Message ID:
20090213182526.GA18087@tetsuo.karasik.eu.org
Hello,

I've just been bitten by an inhertitance case, as described here:

http://perlmonks.org/?node_id=743606

But in short, the problem is such that if you import names into a class that
derives from a parent class, then you risk to silently override parent class
methods without being aware of it. For example, a code like

   package MyCGI;
   use base qw(CGI);
   use POSIX qw(access);
   MyCGI-> new()

may break if next version of CGI.pm may have an important internal "sub access",
that is supposed to be called from new() but mysteriously wouldn't.

I wonder, if solution to this problem is desired for the language.
I investigated a bit and found that a very crude patch (see below)
would do a more "proper" inheritance, so I guess that such a behavior
can be triggered by setting some internal flag, $^H or something similar
that can be made local to a package (I'm unsure if $^H has this feature).

My proposition is twofold: first, I'd like to create means to protect against
blind inheritance problem. Second, I'll also need to ask for help with the
patch, not much, but still, I could easily overlook something or do a plain
wrong. Finally, I'd like to ask for opinions what UI would be appropriate for
this feature, I though that possibly "use base" syntax can be extended for this
purpose, something like use base ':only ParentClass' possibly.

Anyway, please tell me what do you think.

Thanks,
	Dmitry Karasik

diff --git a/gv.c b/gv.c
index 65419bd..561cc8f 100644
--- a/gv.c
+++ b/gv.c
@@ -409,7 +409,7 @@ Perl_gv_fetchmeth(pTHX_ HV *stash, const char *name, STRLEN len, I32 level)
             gv_init(topgv, stash, name, len, TRUE);
         if ((cand_cv = GvCV(topgv))) {
             /* If genuine method or valid cache entry, use it */
-            if (!GvCVGEN(topgv) || GvCVGEN(topgv) == topgen_cmp) {
+            if ((!GvCVGEN(topgv) || GvCVGEN(topgv) == topgen_cmp) && !GvIMPORTED(topgv)) {
                 return topgv;
             }
             else {
@@ -457,7 +457,12 @@ Perl_gv_fetchmeth(pTHX_ HV *stash, const char *name, STRLEN len, I32 level)
         candidate = *gvp;
         assert(candidate);
         if (SvTYPE(candidate) != SVt_PVGV) gv_init(candidate, cstash, name, len, TRUE);
-        if (SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
+        if (
+	    SvTYPE(candidate) == SVt_PVGV && 
+	    (cand_cv = GvCV(candidate)) && 
+	    !GvCVGEN(candidate) &&
+	    !GvIMPORTED(cand_cv)
+	) {
             /*
              * Found real method, cache method in topgv if:
              *  1. topgv has no synonyms (else inheritance crosses wires)
diff --git a/pp_hot.c b/pp_hot.c
index c52a0d6..3b247a5 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -3125,6 +3125,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp)
 	if (he) {
 	    gv = MUTABLE_GV(HeVAL(he));
 	    if (isGV(gv) && GvCV(gv) &&
+		!GvIMPORTED(gv) &&
 		(!GvCVGEN(gv) || GvCVGEN(gv)
                   == (PL_sub_generation + HvMROMETA(stash)->cache_gen)))
 		return MUTABLE_SV(GvCV(gv));


-- 
Sincerely,
	Dmitry Karasik


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About