Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.97k stars 556 forks source link

sv_does is broken #10551

Open p5pRT opened 14 years ago

p5pRT commented 14 years ago

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

Searchable as RT77256$

p5pRT commented 14 years ago

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 commented 12 years ago

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 commented 12 years ago

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

p5pRT commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

From @demerphq

universal_does.patch ```diff 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 checks if the object or class performs the role C. 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 role. To mark that -your own classes perform other roles, override C appropriately. +In addition to named classes that C support C 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 in -place of C safely, as it will return true in all places where C will -return true (provided that any overridden C I C methods behave -appropriately). +place of C on objects safely, as it will return true in all places where +C will return true (provided that any overridden C I C +methods behave appropriately). +By default, classes in Perl perform the C 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 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 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 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 commented 12 years ago

From @cpansprout

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

On 24 June 2012 21​:57\, Johan Vromans \jvromans@&#8203;squirrel\.nl wrote​:

Jesse Luehrs \doy@&#8203;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@&#8203;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 commented 12 years ago

From @demerphq

On 25 June 2012 15​:28\, Father Chrysostomos via RT \perlbug\-followup@&#8203;perl\.org wrote​:

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

On 24 June 2012 21​:57\, Johan Vromans \jvromans@&#8203;squirrel\.nl wrote​:

Jesse Luehrs \doy@&#8203;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@&#8203;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\ 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 commented 12 years ago

From @demerphq

On 25 June 2012 15​:34\, demerphq \demerphq@&#8203;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 commented 12 years ago

From @doy

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

On 24 June 2012 21​:57\, Johan Vromans \jvromans@&#8203;squirrel\.nl wrote​:

Jesse Luehrs \doy@&#8203;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@&#8203;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 commented 12 years ago

From @demerphq

On 25 June 2012 16​:43\, Jesse Luehrs \doy@&#8203;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 commented 12 years ago

From @doy

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

On 25 June 2012 16​:43\, Jesse Luehrs \doy@&#8203;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 commented 12 years ago

From @demerphq

On 25 June 2012 17​:04\, Jesse Luehrs \doy@&#8203;tozt\.net wrote​:

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

On 25 June 2012 16​:43\, Jesse Luehrs \doy@&#8203;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 commented 12 years ago

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 commented 12 years ago

From @demerphq

On 25 June 2012 18​:39\, Johan Vromans \jvromans@&#8203;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 commented 12 years ago

From @sciurius

demerphq \demerphq@&#8203;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 commented 12 years ago

From @doy

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

demerphq \demerphq@&#8203;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 \)" I can replace with some expression like "if (does($foo\, \))"\, I'll be happy. Bonus points if does(\substr($foo\, 0\, 1)\, '${}') and does(\v1.2.3\, '${}') are both true(​:

-doy

p5pRT commented 12 years ago

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 \)" I can replace with some expression like "if (does($foo\, \))"\, 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 commented 12 years ago

From @demerphq

On 25 June 2012 22​:25\, Johan Vromans \jvromans@&#8203;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 \)" I can replace with some expression like "if (does($foo\, \))"\, 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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

From @demerphq

On 25 June 2012 22​:51\, Johan Vromans \jvromans@&#8203;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 commented 12 years ago

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 commented 12 years ago

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 commented 12 years ago

From @demerphq

On 26 June 2012 08​:09\, Johan Vromans \jvromans@&#8203;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 commented 12 years ago

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 commented 12 years ago

From @demerphq

On 26 June 2012 09​:14\, Johan Vromans \jvromans@&#8203;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 commented 12 years ago

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 commented 12 years ago

From @phaylon

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

On 26 June 2012 09​:14\, Johan Vromans \jvromans@&#8203;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 commented 12 years ago

From @sciurius

Robert Sedlacek \rs@&#8203;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 commented 12 years ago

From @phaylon

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

Robert Sedlacek \rs@&#8203;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 commented 12 years ago

From @sciurius

Robert Sedlacek \rs@&#8203;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 commented 11 years ago

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