Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sv_does is broken #10551

Open
p5pRT opened this issue Aug 16, 2010 · 39 comments
Open

sv_does is broken #10551

p5pRT opened this issue Aug 16, 2010 · 39 comments

Comments

@p5pRT
Copy link

p5pRT commented Aug 16, 2010

Migrated from rt.perl.org#77256 (status was 'open')

Searchable as RT77256$

@p5pRT
Copy link
Author

p5pRT commented Aug 16, 2010

From ben@morrow.me.uk

The API function sv_does is broken, and has been since it was first
introduced. What it actually implements is a correct Perl-level ->isa
check, which is useful, but not the same as a ->DOES check.

The logic currently in Perl_sv_does for checking ->isa should be moved
into XS_UNIVERSAL_DOES, and Perl_sv_does itself should just do a normal
->DOES method call. (The checks for 'is this an object' should probably
stay.)

It might be useful to add a sv_perl_isa API, which does a proper
overridable ->isa check, but that is a separate question.

Ben

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @doy

The correct way to test for DOES (or isa, or can) is to just call the
method directly. I'm not sure that providing wrappers around this in the
perl core is particularly useful.

That said, I am kind of curious what the actual use for making sv_does a
public API function is.

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @demerphq

On 24 June 2012 03​:22, Jesse Luehrs via RT <perlbug-followup@​perl.org> wrote​:

The correct way to test for DOES (or isa, or can) is to just call the
method directly. I'm not sure that providing wrappers around this in the
perl core is particularly useful.

That said, I am kind of curious what the actual use for making sv_does a
public API function is.

When does was introduced there was a lot of debate about whether it
made sense. I was one of the people who argued it didnt, and provided
patches to make it make sense.

Now that is has been available in the wild for some time I it is clear
to me it has failed as an idea exactly as predicted.

Maybe I should get my patches together and we can get a DOES that does.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From chromatic@wgz.org

On Saturday, June 23, 2012 06​:22​:34 PM Jesse Luehrs via RT wrote​:

The correct way to test for DOES (or isa, or can) is to just call the
method directly. I'm not sure that providing wrappers around this in the
perl core is particularly useful.

That seems sanest to me.

That said, I am kind of curious what the actual use for making sv_does a
public API function is.

If I recall correctly, it only exists and is public because sv_isa exists and
is public. sv_does is clearly broken unless it calls the method directly.

-- c

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @cpansprout

On Sun Jun 24 09​:50​:04 2012, chromatic@​wgz.org wrote​:

On Saturday, June 23, 2012 06​:22​:34 PM Jesse Luehrs via RT wrote​:

The correct way to test for DOES (or isa, or can) is to just call
the
method directly. I'm not sure that providing wrappers around this in
the
perl core is particularly useful.

That seems sanest to me.

That said, I am kind of curious what the actual use for making
sv_does a
public API function is.

If I recall correctly, it only exists and is public because sv_isa
exists and
is public. sv_does is clearly broken unless it calls the method
directly.

UNIVERSAL​::DOES is implemented in terms of sv_does, so we can’t ‘just’
make it call the method. I think the real bug is that it is in the API.
But there are many weird and useless functions in the API that we can’t
get rid of.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @doy

On Sun, Jun 24, 2012 at 11​:06​:09AM -0700, Father Chrysostomos via RT wrote​:

On Sun Jun 24 09​:50​:04 2012, chromatic@​wgz.org wrote​:

On Saturday, June 23, 2012 06​:22​:34 PM Jesse Luehrs via RT wrote​:

The correct way to test for DOES (or isa, or can) is to just call
the
method directly. I'm not sure that providing wrappers around this in
the
perl core is particularly useful.

That seems sanest to me.

That said, I am kind of curious what the actual use for making
sv_does a
public API function is.

If I recall correctly, it only exists and is public because sv_isa
exists and
is public. sv_does is clearly broken unless it calls the method
directly.

UNIVERSAL​::DOES is implemented in terms of sv_does, so we can’t ‘just’
make it call the method. I think the real bug is that it is in the API.
But there are many weird and useless functions in the API that we can’t
get rid of.

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @tsee

On 06/24/2012 08​:06 PM, Father Chrysostomos via RT wrote​:

UNIVERSAL​::DOES is implemented in terms of sv_does, so we can’t ‘just’
make it call the method. I think the real bug is that it is in the API.
But there are many weird and useless functions in the API that we can’t
get rid of.

But we can move them to a section "for back-compat only" in perlapi.pod
to make sure that sane but uninformed people don't call these functions
in new code.

--Steffen

@p5pRT
Copy link
Author

p5pRT commented Jun 24, 2012

From @sciurius

Jesse Luehrs <doy@​tozt.net> writes​:

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

Last year we had a discussion about this.

DOES, as it is implemented right now, is bogus and wrong. The
documentation talks about DOES in combination with roles but there are
no roles in Perl. Adding "A role is ..." to the documentation of DOES
doens't really help, especially since Perlootut reads​:

  "Perl does not have any built-in way to express roles.
  [...] As we mentioned before, roles provide an alternative to
  inheritance, but Perl does not have any built-in role support. If you
  choose to use Moose, it comes with a full-fledged role implementation.
  However, if you use one of our other recommended OO modules, you can
  still use roles with Role​::Tiny [...]".

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

  if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
  ...
  }

And​:

  if ($foo->does('Some​::Role')) {
  ...
  }

So it does not even use, or advise to use, DOES. Neither does Moo. In
fact there's no need at all for DOES since said CPAN modules provide
their own methods to check whether a class provides a role.

I repeat from <m2mxiy48bv.fsf@​phoenix.squirrel.nl> :

  [...] But since there's no documentation about roles people may use
  DOES as they think fit -- and we have yet another coffin nail that we
  can never get rid of anymore due to compatibility purposes.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 24 June 2012 21​:57, Johan Vromans <jvromans@​squirrel.nl> wrote​:

Jesse Luehrs <doy@​tozt.net> writes​:

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

Last year we had a discussion about this.

DOES, as it is implemented right now, is bogus and wrong. The
documentation talks about DOES in combination with roles but there are
no roles in Perl. Adding "A role is ..." to the documentation of DOES
doens't really help, especially since Perlootut reads​:

 "Perl does not have any built-in way to express roles.
 [...] As we mentioned before, roles provide an alternative to
 inheritance, but Perl does not have any built-in role support. If you
 choose to use Moose, it comes with a full-fledged role implementation.
 However, if you use one of our other recommended OO modules, you can
 still use roles with Role​::Tiny [...]".

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

 if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
  ...
 }

And​:

 if ($foo->does('Some​::Role')) {
   ...
 }

So it does not even use, or advise to use, DOES. Neither does Moo. In
fact there's no need at all for DOES since said CPAN modules provide
their own methods to check whether a class provides a role.

I repeat from <m2mxiy48bv.fsf@​phoenix.squirrel.nl> :

 [...] But since there's no documentation about roles people may use
 DOES as they think fit -- and we have yet another coffin nail that we
 can never get rid of anymore due to compatibility purposes.

It is savable IMO. I posted a patch at the time to make it useful.
Reattached again here.

Thread is available here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2007/03/msg122105.html

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

universal_does.patch
Index: embed.fnc
===================================================================
--- embed.fnc	(revision 1199)
+++ embed.fnc	(working copy)
@@ -829,7 +829,7 @@
 Apd	|void	|sv_dec		|NN SV* sv
 Ap	|void	|sv_dump	|NN SV* sv
 ApdR	|bool	|sv_derived_from|NN SV* sv|NN const char* name
-ApdR	|bool	|sv_does	|NN SV* sv|NN const char* name
+ApdR	|bool	|sv_does	|NN SV* sv|NN const char* name|STRLEN namelen|U32 flags
 Apd	|I32	|sv_eq		|NULLOK SV* sv1|NULLOK SV* sv2
 Apd	|void	|sv_free	|NULLOK SV* sv
 poMX	|void	|sv_free2	|NN SV* sv
Index: lib/UNIVERSAL.pm
===================================================================
--- lib/UNIVERSAL.pm	(revision 1199)
+++ lib/UNIVERSAL.pm	(working copy)
@@ -32,6 +32,8 @@
 
     $does_log = $obj->DOES("Logger");
     $does_log = Class->DOES("Logger");
+    $does_log = UNIVERSAL::DOES($obj,"Logger");
+    $does_array = UNIVERSAL::DOES($obj,'@{}');
 
     $sub      = $obj->can("print");
     $sub      = Class->can("print");
@@ -105,6 +107,8 @@
 
 =item C<< CLASS->DOES( ROLE ) >>
 
+=item C<< UNIVERSAL::DOES( $obj, ROLE ) >>
+
 C<DOES> checks if the object or class performs the role C<ROLE>.  A role is a
 named group of specific behavior (often methods of particular names and
 signatures), similar to a class, but not necessarily a complete class by
@@ -117,17 +121,44 @@
 mandates an inheritance relationship.  Other relationships include aggregation,
 delegation, and mocking.)
 
-By default, classes in Perl only perform the C<UNIVERSAL> role.  To mark that
-your own classes perform other roles, override C<DOES> appropriately.
+In addition to named classes that C<isa> support C<DOES> also provides a safe
+way to query whether an object can be used in certain ways. The special roles
+C<'${}'>, C<'%{}'>, C<'@{}'>, C<'&{}'> and C<'*{}'> can be used to safely 
+determine if an object can be dereferenced in a given way, and the role 
+C<'qr//'> can be used to check if the object will have special behaviour 
+when used in a regex.
 
 There is a relationship between roles and classes, as each class implies the
 existence of a role of the same name.  There is also a relationship between
 inheritance and roles, in that a subclass that inherits from an ancestor class
 implicitly performs any roles its parent performs.  Thus you can use C<DOES> in
-place of C<isa> safely, as it will return true in all places where C<isa> will
-return true (provided that any overridden C<DOES> I<and> C<isa> methods behave
-appropriately).
+place of C<isa> on objects safely, as it will return true in all places where 
+C<isa> will return true (provided that any overridden C<DOES> I<and> C<isa> 
+methods behave appropriately).
 
+By default, classes in Perl perform the C<UNIVERSAL> role, objects are similar 
+but additionally support the role associated to their implementations 
+underlying type.  To mark that your own classes perform other roles, override 
+C<DOES> appropriately (keeping in mind the warning below). This is safe to do 
+as even when UNIVERSAL::DOES() is called in subroutine form, and therefore 
+bypassing inheritance, it will still delegate to the overriden method. 
+
+B<WARNING:> the delegation behaviour of UNIVERSAL::DOES() means that if a 
+custom DOES() method wishes to call the default method provided by UNIVERSAL, 
+such as via C<$self->SUPER::DOES($role)> then it B<MUST> provide an additional 
+true argument to the call to prevent infinite recursion, and even possibly 
+crash perl. For instance the following is safe.
+
+    package Some::Class;
+    sub DOES {
+        my ($self,$role) = @_;
+        return 1 if $role=~/Foo|Bar/i;
+        return $self->SUPER::DOES($role,'no-delegate')
+        # or
+        #return UNIVERSAL::DOES($self,$role,$true_value)
+    }
+
+
 =item C<< $obj->can( METHOD ) >>
 
 =item C<< CLASS->can( METHOD ) >>
Index: t/op/universal.t
===================================================================
--- t/op/universal.t	(revision 1199)
+++ t/op/universal.t	(working copy)
@@ -10,7 +10,7 @@
     require "./test.pl";
 }
 
-plan tests => 110;
+plan tests => 130;
 
 $a = {};
 bless $a, "Bob";
@@ -210,13 +210,49 @@
 
 package Baz;
 
+{
+    package OL;
+    use overload '@{}'=>sub{return []};
+    sub new { return bless {hahah=>1},shift @_ }
+}
+package Not::Deadly;
+# make sure that the no-delegate option to UNIVERSAL::ISA() works
+sub DOES { $_[0]->SUPER::DOES($_[1],'no-delegate') }
+package Really::Deadly;
+# this will go boom if its used, but we want to test that
+# the no-delegate option to UNIVERSAL::ISA() works.
+sub DOES { $_[0]->SUPER::DOES($_[1]) }
+    
 package main;
 ok( Foo->DOES( 'bar' ), 'DOES() should call DOES() on class' );
 ok( Bar->DOES( 'Bar' ), '... and should fall back to isa()' );
 ok( Bar->DOES( 'Foo' ), '... even when inherited' );
 ok( Baz->DOES( 'Baz' ), '... even without inheriting any other DOES()' );
 ok( ! Baz->DOES( 'Foo' ), '... returning true or false appropriately' );
-
+{
+    my @bad=(bless(qr//,'CODE'),bless(sub{},'ARRAY'),
+             OL->new());
+    ok( UNIVERSAL::DOES($bad[0],'qr//'), 'DOES() can handle "qr//"');
+    ok( !UNIVERSAL::DOES($bad[1],'qr//'), 'DOES() can handle "qr//"');
+    ok( !UNIVERSAL::DOES($bad[0],'&{}'), 'DOES() can handle "&{}"');
+    ok( UNIVERSAL::DOES($bad[1],'&{}'), 'DOES() can handle "&{}"');    
+    ok( !UNIVERSAL::DOES($bad[1],'@{}'), 'DOES() can handle "@{}"');
+    ok( UNIVERSAL::DOES($bad[0],'${}'), 'DOES() can handle "${}"');
+    ok( UNIVERSAL::DOES([],'@{}'), 'DOES() can handle "@{}"');
+    ok( UNIVERSAL::DOES([],'ARRAY'), 'DOES() can handle "ARRAY"');
+    ok( UNIVERSAL::DOES([],'ARRAY'), 'DOES() can handle "ARRAY"');
+    ok( UNIVERSAL::DOES($bad[2],'%{}'), 'DOES() can handle overload');
+    ok( UNIVERSAL::DOES($bad[2],'@{}'), 'DOES() can handle overload');
+    ok( UNIVERSAL::DOES(\*_,'*{}'),'DOES() can handle *{}');
+    ok( UNIVERSAL::DOES({},'%{}'),'DOES() can handle %{}');
+}
+ok( UNIVERSAL::DOES('Foo', 'bar' ), 'UNIVERSAL::DOES() should call DOES() on class' );
+ok( UNIVERSAL::DOES('Bar', 'Bar' ), '...... and should fall back to isa()' );
+ok( UNIVERSAL::DOES('Bar', 'Foo' ), '...... even when inherited' );
+ok( UNIVERSAL::DOES('Baz', 'Baz' ), '...... even without inheriting any other DOES()' );
+ok( ! UNIVERSAL::DOES('Baz', 'Foo' ), '...... returning true or false appropriately' );
+ok( ! Not::Deadly->DOES('Baz'), '...possible infinite loop');
+ok( !UNIVERSAL::DOES('Really::Deadly','Baz','no-delegate'), '...possible infinite loop');
 package Pig;
 package Bodine;
 Bodine->isa('Pig');
Index: universal.c
===================================================================
--- universal.c	(revision 1199)
+++ universal.c	(working copy)
@@ -169,56 +169,198 @@
 
 }
 
+
+
+#include "XSUB.h"
+
+/* 
+CHECK_IF_SUB_USED_ON_OBJECT(ITEM,SV_CV)
+
+   utility define for checking to see if UNIVERSAL::DOES() has been
+   called as a subroutine on a class or object that overrides DOES.
+   If it does then we set SV_CV to hold the method which will 
+   mean later on it will get called. 
+   ITEM holds the code required to find the stash of the thing we are
+   looking up.
+*/   
+
+#define CHECK_IF_SUB_USED_ON_OBJECT(FLAGS,ITEM,SV_CV) STMT_START { \
+    if (!((FLAGS) & 1)) { \
+        HV *me = gv_stashpvs("UNIVERSAL", 0); \
+        HV *them = (ITEM); \
+        if (me && them) { \
+            const char *does="DOES"; \
+            GV * const gv_me = gv_fetchmethod_autoload(me, does, FALSE); \
+            GV * const gv_them = gv_fetchmethod_autoload(them, does, FALSE); \
+            if (gv_me != gv_them && gv_me && isGV(gv_me) && gv_them && \
+                isGV(gv_them) && GvCV(gv_me) != GvCV(gv_them)) \
+                    (SV_CV) = (SV*)GvCV(gv_them); \
+        } \
+    } \
+} STMT_END
+
 /*
 =for apidoc sv_does
 
 Returns a boolean indicating whether the SV performs a specific, named role.
 The SV can be a Perl object or the name of a Perl class.
 
+Named roles are as in isa(), with the addition of five special roles for 
+refering to referencing operations that are allowed on the SV. These 
+take the form of ${}, %{}, @{}, &{} and *{}. In addition the role 
+'qr//' is defined which really checks if the reference is an object 
+with regexp magic attached.
+
+Under normal circumstances if this routine detects that the SV is an object or 
+classname which possess its own DOES routine then this routine will delegate 
+to it. To block with then when (flags & 1) is true then no delegation will 
+occur. This is to support the use of Class->SUPER::DOES() without infinite 
+recursion occuring due to delegation.
+
 =cut
 */
-
-#include "XSUB.h"
-
 bool
-Perl_sv_does(pTHX_ SV *sv, const char *name)
+Perl_sv_does(pTHX_ SV *sv, const char *name, STRLEN namelen, U32 flags)
 {
-    const char *classname;
-    bool does_it;
 
-    dSP;
-    ENTER;
-    SAVETMPS;
+    bool does_it = 0;  /* return value */
+    SV *rv = NULL;     /* what thing does sv reference (if any) */
+    bool is_obj = 0;   /* is rv an object? */
+    
+    SV *sv_name = NULL; /* the name but in sv form (why isnt this an argument?) */
+    SV *sv_cv = NULL;   /* if we are going to execute a code ref this is it */
+    const char *subname = NULL; /* what subroutine/method do we execute */
+    int count;          /* how many items did the subroutine execute */
+    
 
-    SvGETMAGIC(sv);
+    SvGETMAGIC(sv);  /* make sure we play nice with magic */
 
+    /* base tests for non object/references */
     if (!SvOK(sv) || !(SvROK(sv) || (SvPOK(sv) && SvCUR(sv))
-		|| (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
-	return FALSE;
-
-    if (sv_isobject(sv)) {
-	classname = sv_reftype(SvRV(sv),TRUE);
-    } else {
-	classname = SvPV(sv,PL_na);
+                || (SvGMAGICAL(sv) && SvPOKp(sv) && SvCUR(sv))))
+        return FALSE;
+    
+    if (SvROK(sv)) { /* is it a reference ?*/
+        rv = (SV*)SvRV(sv); /* to what? */
+        if (rv && SvOBJECT(rv)) { /* is it an object? */
+            is_obj = 1;
+            /* check to see if we are in the wrong DOES code 
+               such as if they say UNIVERSAL::DOES($x,$y) but $x 
+               has a overridden DOES with something else. */
+            CHECK_IF_SUB_USED_ON_OBJECT(flags, SvSTASH(rv),sv_cv);
+        }
     }
 
-    if (strEQ(name,classname))
-	return TRUE;
+    if (!sv_cv) { /* no overriden method to be called */
+        /* check if we are checking a special internal role */
+        if (namelen == 4 && strEQ(name,"qr//")) { 
+            /* does sv have regexp magic associated to it? */
+            if (is_obj && SvTYPE(rv) == SVt_PVMG && mg_find(rv, PERL_MAGIC_qr))
+                return 1;
+            else
+                return 0;
+        } else if ( namelen == 3 && name[1]=='{' && name[2]=='}' ) {
+            /* Check to see how things can be dereferenced */
+            const svtype t = SvTYPE(rv);
+            switch (t) {
+            case SVt_NULL:
+            case SVt_IV:
+            case SVt_NV:
+            case SVt_RV:
+            case SVt_PV:
+            case SVt_PVIV:
+            case SVt_PVNV:
+            case SVt_PVMG:
+            case SVt_PVLV:
+                if (name[0] == '$') return 1;
+                break;
+            case SVt_PVAV:  
+                if (name[0] == '@') return 1;
+                break;
+            case SVt_PVHV:  if (name[0] == '%') return 1;
+                break;
+            case SVt_PVCV:  
+                if (name[0] == '&') return 1;
+                break;
+            case SVt_PVGV:  
+                if (name[0] == '*') return 1;
+                break;
+            case SVt_PVFM:
+            case SVt_PVIO:
+            case SVt_BIND:
+            default:        
+                break;
+            }
+            
+            if (is_obj) {
+                /* we need check to see if the object overloads dereferencing 
+                   but to do that we need to ensure overload has been loaded 
+                 */
+                dSP;
+                PUTBACK;
+                ENTER;
 
-    PUSHMARK(SP);
-    XPUSHs(sv);
-    XPUSHs(sv_2mortal(newSVpv(name, 0)));
-    PUTBACK;
+                Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT,
+                    newSVpvs("overload") , NULL);
 
-    call_method("isa", G_SCALAR);
-    SPAGAIN;
+                LEAVE;
+                SPAGAIN;
 
-    does_it = SvTRUE( TOPs );
-    FREETMPS;
-    LEAVE;
+                sv_name = sv_2mortal( newSVpv( name, namelen ) );
+                subname = "overload::Method";
+            } else
+                return 0;
+        } else {
+            /* Check to see if the object supports a named role */
+            const char *classname;
+            if (is_obj) {
+                classname = sv_reftype(rv,TRUE);
+            } else {
+                CHECK_IF_SUB_USED_ON_OBJECT(flags,gv_stashsv(sv, 0),sv_cv);
+                classname = SvPV(sv,PL_na);
+            }
+            if (!sv_cv) { 
+                if ( strEQ( name, classname ))
+                    return TRUE;
+                
+                sv_name = sv_2mortal( newSVpv( name, namelen ) );
+                if (rv && !is_obj)
+                    subname = "UNIVERSAL::isa";
+                else
+                    subname = "isa";
+            }                    
+        }
+    }
+    /* everything before this moment was in preparation for now */
+    {
+        /* call the final routine which will decide things */
+        dSP;
+        ENTER;
+        SAVETMPS;
+        PUSHMARK(SP);
+        XPUSHs(sv);
+        XPUSHs(sv_name);
+        PUTBACK;
 
+        if (sv_cv)
+            count = call_sv(sv_cv,G_SCALAR);
+        else if (subname[0]=='i') /* 'i' for "isa" */
+            count = call_method(subname, G_SCALAR);
+        else
+            count = call_pv(subname,G_SCALAR);
+
+        SPAGAIN;
+        if (count != 1)
+            Perl_croak(aTHX_ "panic: DOES helper method returned "
+                " incorrect number of values\n") ;
+        does_it = SvTRUE( TOPs );
+        FREETMPS;
+        LEAVE;
+    }
+
     return does_it;
 }
+#undef CHECK_IF_SUB_USED_ON_OBJECT
 
 regexp *
 Perl_get_re_arg( pTHX_ SV *sv, U32 flags, MAGIC **mgp) {
@@ -413,16 +555,21 @@
 {
     dVAR;
     dXSARGS;
+    U32 flags = 0;
     PERL_UNUSED_ARG(cv);
+    
 
-    if (items != 2)
-	Perl_croak(aTHX_ "Usage: invocant->does(kind)");
-    else {
-	SV * const sv = ST(0);
-	const char *name;
-
-	name = SvPV_nolen_const(ST(1));
-	if (sv_does( sv, name ))
+    if (items == 3) {
+        if (SvTRUE(ST(2))) flags |= 1;
+    } else if (items != 2)
+	Perl_croak(aTHX_ "Usage: invocant->DOES(kind[,no_delegate])");
+	
+    {
+        SV * const sv = ST(0);
+        STRLEN name_len;
+	const char *name = SvPV(ST(1), name_len);
+	
+	if (Perl_sv_does( aTHX_ sv, name, name_len, flags ))
 	    XSRETURN_YES;
 
 	XSRETURN_NO;

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @cpansprout

On Sun Jun 24 23​:48​:39 2012, demerphq wrote​:

On 24 June 2012 21​:57, Johan Vromans <jvromans@​squirrel.nl> wrote​:

Jesse Luehrs <doy@​tozt.net> writes​:

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

Last year we had a discussion about this.

DOES, as it is implemented right now, is bogus and wrong. The
documentation talks about DOES in combination with roles but there are
no roles in Perl. Adding "A role is ..." to the documentation of DOES
doens't really help, especially since Perlootut reads​:

�"Perl does not have any built-in way to express roles.
�[...] As we mentioned before, roles provide an alternative to
�inheritance, but Perl does not have any built-in role support. If you
�choose to use Moose, it comes with a full-fledged role implementation.
�However, if you use one of our other recommended OO modules, you can
�still use roles with Role​::Tiny [...]".

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

�if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
� ...
�}

And​:

�if ($foo->does('Some​::Role')) {
� �...
�}

So it does not even use, or advise to use, DOES. Neither does Moo. In
fact there's no need at all for DOES since said CPAN modules provide
their own methods to check whether a class provides a role.

I repeat from <m2mxiy48bv.fsf@​phoenix.squirrel.nl> :

�[...] But since there's no documentation about roles people may use
�DOES as they think fit -- and we have yet another coffin nail that we
�can never get rid of anymore due to compatibility purposes.

It is savable IMO. I posted a patch at the time to make it useful.
Reattached again here.

Thread is available here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2007/03/msg122105.html

Having UNIVERSAL​::DOES call the method could cause infinite looping if
someone says sub DOES { goto &UNIVERSAL​::does } (whether in a subclass
or a wrapper).

Having built-in roles like qr// sounds like a nice idea, but don’t we
already have that with Regexp, HASH, ARRAY, etc.?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 15​:28, Father Chrysostomos via RT
<perlbug-followup@​perl.org> wrote​:

On Sun Jun 24 23​:48​:39 2012, demerphq wrote​:

On 24 June 2012 21​:57, Johan Vromans <jvromans@​squirrel.nl> wrote​:

Jesse Luehrs <doy@​tozt.net> writes​:

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

Last year we had a discussion about this.

DOES, as it is implemented right now, is bogus and wrong. The
documentation talks about DOES in combination with roles but there are
no roles in Perl. Adding "A role is ..." to the documentation of DOES
doens't really help, especially since Perlootut reads​:

�"Perl does not have any built-in way to express roles.
�[...] As we mentioned before, roles provide an alternative to
�inheritance, but Perl does not have any built-in role support. If you
�choose to use Moose, it comes with a full-fledged role implementation.
�However, if you use one of our other recommended OO modules, you can
�still use roles with Role​::Tiny [...]".

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

�if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
� ...
�}

And​:

�if ($foo->does('Some​::Role')) {
� �...
�}

So it does not even use, or advise to use, DOES. Neither does Moo. In
fact there's no need at all for DOES since said CPAN modules provide
their own methods to check whether a class provides a role.

I repeat from <m2mxiy48bv.fsf@​phoenix.squirrel.nl> :

�[...] But since there's no documentation about roles people may use
�DOES as they think fit -- and we have yet another coffin nail that we
�can never get rid of anymore due to compatibility purposes.

It is savable IMO. I posted a patch at the time to make it useful.
Reattached again here.

Thread is available here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2007/03/msg122105.html

Having UNIVERSAL​::DOES call the method could cause infinite looping if
someone says sub DOES { goto &UNIVERSAL​::does } (whether in a subclass
or a wrapper).

The patch explains how to do this properly doesn't it?

+B<WARNING​:> the delegation behaviour of UNIVERSAL​::DOES() means that if a
+custom DOES() method wishes to call the default method provided by UNIVERSAL,
+such as via C<$self->SUPER​::DOES($role)> then it B<MUST> provide an additional
+true argument to the call to prevent infinite recursion, and even possibly
+crash perl. For instance the following is safe.
+
+ package Some​::Class;
+ sub DOES {
+ my ($self,$role) = @​_;
+ return 1 if $role=~/Foo|Bar/i;
+ return $self->SUPER​::DOES($role,'no-delegate')
+ # or
+ #return UNIVERSAL​::DOES($self,$role,$true_value)
+ }

Im not thrilled that this edge case is a possibility but I figured it
was simple enough to say "well dont do that then", although I suspect
these days I could figure out a block, albeit at potentially a
performance trade off to prevent people from being overly stupid. But
IMO you could make exactly the same argument about a number of places
couldn't you? Can't I infinite loop if I create an overload sub with a
similar level of carelessness? Does that mean we should rip out
overload?

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 15​:34, demerphq <demerphq@​gmail.com> wrote​:

But IMO you could make exactly the same argument about a number of places
couldn't you? Can't I infinite loop if I create an overload sub with a
similar level of carelessness? Does that mean we should rip out
overload?

Eg​:

cat perl overload_inf.pl
cat​: perl​: No such file or directory
package Foo;
use overload '""'=> \&stringify;

sub stringify {
  print "in stringify\n";
  return "" . $_[0];
}

my $obj= bless {},"Foo";
print $obj

Also loops infinitely and eventually segfaults perl. So to the extent
your comment is criticism of my patch, I think its a bit unfair to
apply it in this case given we have loads of other cases where it also
applies.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @doy

On Mon, Jun 25, 2012 at 08​:48​:00AM +0200, demerphq wrote​:

On 24 June 2012 21​:57, Johan Vromans <jvromans@​squirrel.nl> wrote​:

Jesse Luehrs <doy@​tozt.net> writes​:

Yes, the implementation of UNIVERSAL​::DOES is fine, the only confusing
part is that sv_does is a public API function.

Last year we had a discussion about this.

DOES, as it is implemented right now, is bogus and wrong. The
documentation talks about DOES in combination with roles but there are
no roles in Perl. Adding "A role is ..." to the documentation of DOES
doens't really help, especially since Perlootut reads​:

 "Perl does not have any built-in way to express roles.
 [...] As we mentioned before, roles provide an alternative to
 inheritance, but Perl does not have any built-in role support. If you
 choose to use Moose, it comes with a full-fledged role implementation.
 However, if you use one of our other recommended OO modules, you can
 still use roles with Role​::Tiny [...]".

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

 if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
  ...
 }

And​:

 if ($foo->does('Some​::Role')) {
   ...
 }

So it does not even use, or advise to use, DOES. Neither does Moo. In
fact there's no need at all for DOES since said CPAN modules provide
their own methods to check whether a class provides a role.

I repeat from <m2mxiy48bv.fsf@​phoenix.squirrel.nl> :

 [...] But since there's no documentation about roles people may use
 DOES as they think fit -- and we have yet another coffin nail that we
 can never get rid of anymore due to compatibility purposes.

It is savable IMO. I posted a patch at the time to make it useful.
Reattached again here.

Thread is available here​:

http​://www.nntp.perl.org/group/perl.perl5.porters/2007/03/msg122105.html

cheers,
Yves

So I like the general concept here, but I don't know if I'm a huge fan
of the implementation. Requiring the hack that you have to explicitly
say "don't recurse" is a bit ugly, and the only reason it's necessary is
because you're forcing UNIVERSAL​::DOES to be able to be called as both a
function and a method. This is concerning because of the amount of
effort that we have had to put in to convince people to *not* do this
with UNIVERSAL​::isa and UNIVERSAL​::can, because they do not handle this
sort of thing properly.

I think this would work a lot better if UNIVERSAL​::DOES was only called
as a method, and a new keyword/function of some sort were introduced to
either call DOES as a method on its argument, or handle the various
things that can't have methods called on them (or alternately, we can
wait until autoboxing gets into core? (​: ).

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 16​:43, Jesse Luehrs <doy@​tozt.net> wrote​:

I think this would work a lot better if UNIVERSAL​::DOES was only called
as a method, and a new keyword/function of some sort were introduced to
either call DOES as a method on its argument, or handle the various
things that can't have methods called on them (or alternately, we can
wait until autoboxing gets into core? (​: ).

This doesnt fly as you then restrict the use of DOES to objects and
you have to guard any use of it with a blessed() check, which is IMO
one of the reasons why it goes almost completely unused in production
code.

Perhaps there is an alternative but "must be called as a method" isn't
the right one.

cheers
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @doy

On Mon, Jun 25, 2012 at 04​:59​:18PM +0200, demerphq wrote​:

On 25 June 2012 16​:43, Jesse Luehrs <doy@​tozt.net> wrote​:

I think this would work a lot better if UNIVERSAL​::DOES was only called
as a method, and a new keyword/function of some sort were introduced to
either call DOES as a method on its argument, or handle the various
things that can't have methods called on them (or alternately, we can
wait until autoboxing gets into core? (​: ).

This doesnt fly as you then restrict the use of DOES to objects and
you have to guard any use of it with a blessed() check, which is IMO
one of the reasons why it goes almost completely unused in production
code.

Perhaps there is an alternative but "must be called as a method" isn't
the right one.

No, you misunderstood - introduce a new separate keyword which itself
calls DOES as a method on objects, and does whatever is appropriate for
non-objects. This way, you can do "if (does([], '@​{}'))" or
"if (does(Foo->new, 'SomeRole'))" and have both of those do sensible
things, without having the issue of having to hack things around in
order to make UNIVERSAL​::DOES callable as a function.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 17​:04, Jesse Luehrs <doy@​tozt.net> wrote​:

On Mon, Jun 25, 2012 at 04​:59​:18PM +0200, demerphq wrote​:

On 25 June 2012 16​:43, Jesse Luehrs <doy@​tozt.net> wrote​:

I think this would work a lot better if UNIVERSAL​::DOES was only called
as a method, and a new keyword/function of some sort were introduced to
either call DOES as a method on its argument, or handle the various
things that can't have methods called on them (or alternately, we can
wait until autoboxing gets into core? (​: ).

This doesnt fly as you then restrict the use of DOES to objects and
you have to guard any use of it with a blessed() check, which is IMO
one of the reasons why it goes almost completely unused in production
code.

Perhaps there is an alternative but "must be called as a method" isn't
the right one.

No, you misunderstood - introduce a new separate keyword which itself
calls DOES as a method on objects, and does whatever is appropriate for
non-objects. This way, you can do "if (does([], '@​{}'))" or
"if (does(Foo->new, 'SomeRole'))" and have both of those do sensible
things, without having the issue of having to hack things around in
order to make UNIVERSAL​::DOES callable as a function.

Ah. Yes I did misunderstand. Thanks for clarifying.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @sciurius

[Quoting Jesse Luehrs, on June 25 2012, 10​:04, in "Re​: [perl #77256] sv"]

introduce a new separate keyword which itself
calls DOES as a method on objects, and does whatever is appropriate for
non-objects. This way, you can do "if (does([], '@​{}'))"

Great! Finally we'd get rid of isa($foo, 'ARRAY') ...

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 18​:39, Johan Vromans <jvromans@​squirrel.nl> wrote​:

[Quoting Jesse Luehrs, on June 25 2012, 10​:04, in "Re​: [perl #77256] sv"]

introduce a new separate keyword which itself
calls DOES as a method on objects, and does whatever is appropriate for
non-objects. This way, you can do "if (does([], '@​{}'))"

Great! Finally we'd get rid of isa($foo, 'ARRAY') ...

If Ricardo is fine with something like this then I am willing to do
the work to get my patch into shape.

cheers,
Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @sciurius

demerphq <demerphq@​gmail.com> writes​:

If Ricardo is fine with something like this then I am willing to do
the work to get my patch into shape.

Do we already have a list of predefined rules (like '@​{}' that you used
as an example earlier)?

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @doy

On Mon, Jun 25, 2012 at 07​:46​:22PM +0200, Johan Vromans wrote​:

demerphq <demerphq@​gmail.com> writes​:

If Ricardo is fine with something like this then I am willing to do
the work to get my patch into shape.

Do we already have a list of predefined rules (like '@​{}' that you used
as an example earlier)?

As long as anywhere that I'm currently doing
"if (ref($foo) eq <something>)" I
can replace with some expression like
"if (does($foo, <something else>))", I'll be happy. Bonus points if
does(\substr($foo, 0, 1), '${}') and does(\v1.2.3, '${}') are both
true(​:

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @sciurius

[Quoting Jesse Luehrs, on June 25 2012, 12​:56, in "Re​: [perl #77256] sv"]

As long as anywhere that I'm currently doing
"if (ref($foo) eq <something>)" I
can replace with some expression like
"if (does($foo, <something else>))", I'll be happy.

I'd expect​:

  my $a = bless [], "Foo";
  say "Foo" if does($a, 'Foo'); # says "Foo"
  say "Array" if does($a, '[]'); # says "Array"

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 22​:25, Johan Vromans <jvromans@​squirrel.nl> wrote​:

[Quoting Jesse Luehrs, on June 25 2012, 12​:56, in "Re​: [perl #77256] sv"]

As long as anywhere that I'm currently doing
"if (ref($foo) eq <something>)" I
can replace with some expression like
"if (does($foo, <something else>))", I'll be happy.

I'd expect​:

 my $a = bless [], "Foo";
 say "Foo"   if does($a, 'Foo');       # says "Foo"
 say "Array" if does($a, '[]');        # says "Array"

The patch would want you to write that as​:

does($a,"ARRAY")

Just as you would with UNIVERSAL​::isa().

but it supports

say "Array-like" if does($a, '@​{}');        # says "Array"

if you wanted to know if you could pretend it was an array.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @sciurius

[Quoting demerphq, on June 25 2012, 22​:42, in "Re​: [perl #77256] sv"]

 my $a = bless [], "Foo";
 say "Foo"   if does($a, 'Foo');       # says "Foo"
 say "Array" if does($a, '[]');        # says "Array"

The patch would want you to write that as​:

does($a,"ARRAY")

Just as you would with UNIVERSAL​::isa().

but it supports

say "Array-like" if does($a, '@​{}');        # says "Array"

if you wanted to know if you could pretend it was an array.

I think we might be missing an opportunity here.

A( ref to a)n array that's blessed seems to me an excellent case for
supporting two roles​: the array role and the object role. It's not
array-like, it is not less an array as [].

So, if

  does( [], 'ARRAY' ); # true
  my $a = [];
  does( $a, 'ARRAY' ); # true

then

  $a = bless [], 'Foo';
  does( $a, 'ARRAY'); # should be true as well

Maybe it helps if you explain the difference between

  does( ..., 'ARRAY' )

and

  does( ..., '@​{}' )

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @doy

On Mon, Jun 25, 2012 at 10​:51​:00PM +0200, Johan Vromans wrote​:

[Quoting demerphq, on June 25 2012, 22​:42, in "Re​: [perl #77256] sv"]

 my $a = bless [], "Foo";
 say "Foo"   if does($a, 'Foo');       # says "Foo"
 say "Array" if does($a, '[]');        # says "Array"

The patch would want you to write that as​:

does($a,"ARRAY")

Just as you would with UNIVERSAL​::isa().

but it supports

say "Array-like" if does($a, '@​{}');        # says "Array"

if you wanted to know if you could pretend it was an array.

I think we might be missing an opportunity here.

A( ref to a)n array that's blessed seems to me an excellent case for
supporting two roles​: the array role and the object role. It's not
array-like, it is not less an array as [].

So, if

does( [], 'ARRAY' ); # true
my $a = [];
does( $a, 'ARRAY' ); # true

then

$a = bless [], 'Foo';
does( $a, 'ARRAY'); # should be true as well

Maybe it helps if you explain the difference between

does( ..., 'ARRAY' )

and

does( ..., '@​{}' )

I imagine that does(..., '@​{}') takes overloading into account. One
thing that makes this less than ideal though is that $foo->$bar only
looks up string overloading on $bar, and not &{} overloading. It'd be
nice if that were fixed, since it would be a bit misleading for
does($o, '&{}) to be true, but for $thing->$o to fail.

-doy

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @phaylon

On Mon, 2012-06-25 at 15​:55 -0500, Jesse Luehrs wrote​:

On Mon, Jun 25, 2012 at 10​:51​:00PM +0200, Johan Vromans wrote​:

Maybe it helps if you explain the difference between

does( ..., 'ARRAY' )

and

does( ..., '@​{}' )

I imagine that does(..., '@​{}') takes overloading into account.

It might also be a good idea if it were to ignore the actual type of the
blessed hash ref. In most cases if I receive an object instead of a
hash, I only want to use it as such if it makes this intent clear by
overloading.

regards,
Robert

@p5pRT
Copy link
Author

p5pRT commented Jun 25, 2012

From @demerphq

On 25 June 2012 22​:51, Johan Vromans <jvromans@​squirrel.nl> wrote​:

[Quoting demerphq, on June 25 2012, 22​:42, in "Re​: [perl #77256] sv"]

 my $a = bless [], "Foo";
 say "Foo"   if does($a, 'Foo');       # says "Foo"
 say "Array" if does($a, '[]');        # says "Array"

The patch would want you to write that as​:

does($a,"ARRAY")

Just as you would with UNIVERSAL​::isa().

but it supports

say "Array-like" if does($a, '@​{}');        # says "Array"

if you wanted to know if you could pretend it was an array.

I think we might be missing an opportunity here.

A( ref to a)n array that's blessed seems to me an excellent case for
supporting two roles​: the array role and the object role. It's not
array-like, it is not less an array as [].

So, if

 does( [], 'ARRAY' );    # true
 my $a = [];
 does( $a, 'ARRAY' );    # true

then

 $a = bless [], 'Foo';
 does( $a, 'ARRAY');     # should be true as well

Maybe it helps if you explain the difference between

 does( ..., 'ARRAY' )

Same as isa( ..., 'ARRAY'), so it returns true if the reftype(...) eq
'ARRAY' or if the ... was blessed into the 'ARRAY' namespace.

Which actually says you are right and we need a does( ..., '[]') to
tell if it is reftype eq 'ARRAY'.

and

 does( ..., '@​{}'   )

The idea was to tell you if the object was reftype eq 'ARRAY' OR that
there was a '@​{}' overload method defined for the object.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From chromatic@wgz.org

On Sunday, June 24, 2012 09​:57​:59 PM Johan Vromans wrote​:

DOES, as it is implemented right now, is bogus and wrong.

So there are no roles in Perl, but there are some CPAN modules that
implement something role-like. Differently. Role​::Tiny documents​:

if (Role​::Tiny​::does_role($foo, 'Some​::Role')) {
...
}

And​:

if ($foo->does('Some​::Role')) {
...
}

So it does not even use, or advise to use, DOES. Neither does Moo.

Any CPAN module which reimplements a part of the core, badly, has a bug, in my
opinion.

-- c

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @sciurius

[Quoting demerphq, on June 25 2012, 23​:18, in "Re​: [perl #77256] sv"]

 does( ..., 'ARRAY' )

Same as isa( ..., 'ARRAY'), so it returns true if the reftype(...) eq
'ARRAY' or if the ... was blessed into the 'ARRAY' namespace.

Which actually says you are right and we need a does( ..., '[]') to
tell if it is reftype eq 'ARRAY'.

No! This is the fundamental difference between isa and does. does
applies to roles and doesn't consider the actual type.

does( $thing, 'ARRAY' ) being true means I can do $thing->[0] and
push( $thing, ...) and so on. Regardless whether $thing is blessed or
whatever.

There are no other array-oriented roles than 'ARRAY'. Overloading must
always be taken into account, that's the whole idea.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @demerphq

On 26 June 2012 08​:09, Johan Vromans <jvromans@​squirrel.nl> wrote​:

[Quoting demerphq, on June 25 2012, 23​:18, in "Re​: [perl #77256] sv"]

 does( ..., 'ARRAY' )

Same as isa( ..., 'ARRAY'), so it returns true if the reftype(...) eq
'ARRAY' or if the ... was blessed into the 'ARRAY' namespace.

Which actually says you are right and we need a does( ..., '[]') to
tell if it is reftype eq 'ARRAY'.

No! This is the fundamental difference between isa and does. does
applies to roles and doesn't consider the actual type.
does( $thing, 'ARRAY' ) being true means I can do $thing->[0] and
push( $thing, ...) and so on. Regardless whether $thing is blessed or
whatever.

There are no other array-oriented roles than 'ARRAY'. Overloading must
always be taken into account, that's the whole idea.

No no. Sometime you WANT an AV and I dont see how its useful to force
a mental model on devs that forbids then doing something want to do.

This is part of the point for me, DOES and Perls OO model shouldnt
enforce restrictive models on the user base. We should provide the
tools they need to make intelligent decisions on their own. That to me
is the nature of Perl.

Cheers,
yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @sciurius

[Quoting demerphq, on June 26 2012, 08​:49, in "Re​: [perl #77256] sv"]

No no. Sometime you WANT an AV and I dont see how its useful to
force a mental model on devs that forbids then doing something want
to do.

Yes, naturally. Only that's not a role for does, we have reftype for
that.

This is part of the point for me, DOES and Perls OO model shouldnt
enforce restrictive models on the user base. We should provide the
tools they need to make intelligent decisions on their own. That to me
is the nature of Perl.

You risk ending up with several functions with much overlapping
functionality. That is confusing and error prone.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @demerphq

On 26 June 2012 09​:14, Johan Vromans <jvromans@​squirrel.nl> wrote​:

[Quoting demerphq, on June 26 2012, 08​:49, in "Re​: [perl #77256] sv"]

No no. Sometime you WANT an AV and I dont see how its useful to
force a mental model on devs that forbids then doing something want
to do.

Yes, naturally. Only that's not a role for does, we have reftype for
that.

I want one routine that I can use for all of it.

This is part of the point for me, DOES and Perls OO model shouldnt
enforce restrictive models on the user base. We should provide the
tools they need to make intelligent decisions on their own. That to me
is the nature of Perl.

You risk ending up with several functions with much overlapping
functionality. That is confusing and error prone.

Like pack? I think the uses are related enough that people wont be confused.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @sciurius

[Quoting demerphq, on June 26 2012, 09​:19, in "Re​: [perl #77256] sv"]

I want one routine that I can use for all of it.

Let's agree to disagree, then.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @phaylon

On Tue, 2012-06-26 at 09​:19 +0200, demerphq wrote​:

On 26 June 2012 09​:14, Johan Vromans <jvromans@​squirrel.nl> wrote​:

Yes, naturally. Only that's not a role for does, we have reftype for
that.

I want one routine that I can use for all of it.

That would mean the check would break encapsulation by default. It means
I can't use it in any of the use-cases I'd like to use it in. And having
a core utility suggest that poking my objects is OK because I chose to
implement them as a blessed hash ref seems wrong. In my mind, that's
what overloading is for.

This is part of the point for me, DOES and Perls OO model shouldnt
enforce restrictive models on the user base. We should provide the
tools they need to make intelligent decisions on their own. That to me
is the nature of Perl.

You risk ending up with several functions with much overlapping
functionality. That is confusing and error prone.

Like pack? I think the uses are related enough that people wont be confused.

In my mind, 'does' & Co. are about intents. An unblessed hash reference
is intended to be used as a hash reference. An object overloading hash
access is intended for usage as hash reference. But you can not assume
an object likes to be treated as a hash reference just because its
storage is based on it. I'd guess that "does this value want to be
treated like a hash?" is a question asked much more often than "Is this
a hash or something using one to implement an object?".

If an object would _want_ to be used as a hash reference, it could just
override DOES and return true on whatever it wants.

regards,
Robert

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @sciurius

Robert Sedlacek <rs@​474.at> writes​:

If an object would _want_ to be used as a hash reference, it could just
override DOES and return true on whatever it wants.

This would make more sense if perl had opaque objects.
But I won't mind a more stricter 'does'.

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 26, 2012

From @phaylon

On Tue, 2012-06-26 at 17​:23 +0200, Johan Vromans wrote​:

Robert Sedlacek <rs@​474.at> writes​:

If an object would _want_ to be used as a hash reference, it could just
override DOES and return true on whatever it wants.

This would make more sense if perl had opaque objects.
But I won't mind a more stricter 'does'.

It might make more sense, but I think it makes enough already, at least
to me :) 'does' would tell you for every normal object that it wants to
be treated as opaque. If one wants to use blessing just as a way of
having a hash reference with methods, it could be as easy as

  use intent​::hash; # provides a DOES that is true for hash access

I can certainly see the value of reftype and co, sometimes you want to
act on a object on a different level than usage, like serialisation and
transmission, as well as debugging. But I think these are more special
use cases than simply determining if I can use a value like I intend to,
or decide what to do with it depending on how it is intended to be used.

regards,
Robert

@p5pRT
Copy link
Author

p5pRT commented Jun 27, 2012

From @sciurius

Robert Sedlacek <rs@​474.at> writes​:

If one wants to use blessing just as a way of
having a hash reference with methods, it could be as easy as

use intent​::hash; # provides a DOES that is true for hash access

That's precisely what I was thinking of. A nice, clean and elegant way
to achieve the desired behaviour without the need to (re)define magic
subroutines.

+1

-- Johan

@p5pRT
Copy link
Author

p5pRT commented Jun 17, 2013

From @jkeenan

On Mon Aug 16 16​:02​:16 2010, ben@​morrow.me.uk wrote​:

The API function sv_does is broken, and has been since it was first
introduced. What it actually implements is a correct Perl-level ->isa
check, which is useful, but not the same as a ->DOES check.

The logic currently in Perl_sv_does for checking ->isa should be moved
into XS_UNIVERSAL_DOES, and Perl_sv_does itself should just do a normal
->DOES method call. (The checks for 'is this an object' should probably
stay.)

It might be useful to add a sv_perl_isa API, which does a proper
overridable ->isa check, but that is a separate question.

Ben

I reviewed this older ticket tonight. What I quote above was the
original post. Discussion continued from August 2010 to June 2012, but
at no point was a patch submitted. The discussion was of the kind that
we have a lot of on the p5p mailing list and probably should have been
conducted there.

I would like to ask those who posted to review their comments and, as
appropriate, either (a) post on p5p; or (b) open new RT tickets *with
patches*.

I am taking this ticket for the purpose of closing it within 7 days
unless someone wishes to take it over and move the discussion forward.

Thank you very much.
Jim Keenan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants