Git Product home page Git Product logo

p5-mop-redux's Introduction

THIS PROJECT IS DEPRECATED

Build Status Coverage Status

A(nother) MOP for Perl 5

This is a second attempt at building a MOP for Perl 5, this time with significantly scaled back ambition.

The goal is to still have the same syntax, but to make the MOP itself much less complicated, therefore hopefully making the implementation ultimately more maintainable. Additionally this is being built from the start to be compatible with old-style Perl 5 objects and to try to lean on existing Perl conventions instead of inventing a bunch of new things.

Contributing

  • Port existing Perl projects to use mop; tell us what breaks.

p5-mop-redux's People

Contributors

doy avatar fgabolde avatar maettu avatar pangyre avatar perigrin avatar pwbennett avatar rafl avatar stevan avatar tobyink avatar tsee avatar wolfsage avatar xdg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

p5-mop-redux's Issues

submethods' odd behaviour

Some or perhaps all of these might be wrong.

$ perl -Ilib -Mmop -E'class Foo { submethod private { 42 }; method public { $self->private } } class Bar extends Foo { } say Bar->new->public'
Could not find private in Bar=SCALAR(0x982ce68) at lib/mop/internals/mro.pm line 141
$ perl -Ilib -Mmop -E'class Foo { submethod private { 42 }; method public { $self->private } } class Bar extends Foo { submethod private { 666 } } say Bar->new->public'
666
$ perl -Ilib -Mmop -E'class Foo { submethod private { 42 }; method public { $self->private } } class Bar extends Foo { method private { 666 } } say Bar->new->public'
666

Can't close over attribute

Given the simple class

class Foo {
  has $!attr = 0;
  method make_closure {
    return sub { say ++$!attr }
  }
}

I would expect the code

$c1 = Foo->new->make_closure;
$c2 = Foo->new->make_closure;
&$c1; &$c2; &$c1;

to output 1 1 2. However, we get 1 2 3 and a load of errors, because $instance is undef at line 90 of attribute.pm.

The invocant which the anonymous sub has closed over is not available in the dynamic scope of the $c1 invocation, therefore attribute lookup does not seem to work.

Do not allow $self in non-sensical places

has $self; should die.

It is perhaps debatable, but the use of $self in a subroutine signature should also die. Unless of course we start supporting $self: the "invocant" marker on sigs.

Accessor performance mop(Jul 21, 2013) vs Class::Accessor::Fast vs direct hash

use mop;
use Data::Dumper;

class mopClass {
  has $foo is rw;
}


package ClassAccessorFastClass;
use strict;
use warnings;
use base 'Class::Accessor::Fast';

__PACKAGE__->mk_accessors('foo');

package main;

use Benchmark qw/timethese cmpthese/;

my $mop_obj = mopClass->new;
my $class_accessor_fast_obj = ClassAccessorFastClass->new;
my $hash = {};

my $result = timethese(100000, {
  # mop accessor
  mop_accessor => sub {
    $mop_obj->foo('Hello');
    my $foo = $mop_obj->foo;
  },
  # Class::Accessor::Fast accessor
  accessor_fast_accessor => sub {
    $class_accessor_fast_obj->foo('Hello');
    my $foo = $class_accessor_fast_obj->foo;
  },
  # Direct hash
  direct_hash => sub {
    $hash->{foo} = 'Hello';
    my $foo = $hash->{foo};
  }
});

cmpthese $result;

Result.

Benchmark: timing 100000 iterations of accessor_fast_accessor, direct_hash, mop_accessor...
accessor_fast_accessor:  1 wallclock secs ( 0.17 usr +  0.00 sys =  0.17 CPU) @ 588235.29/s (n=100000)
            (warning: too few iterations for a reliable count)
direct_hash:  0 wallclock secs ( 0.04 usr +  0.00 sys =  0.04 CPU) @ 2500000.00/s (n=100000)
            (warning: too few iterations for a reliable count)
mop_accessor: 17 wallclock secs (17.22 usr +  0.06 sys = 17.28 CPU) @ 5787.04/s (n=100000)
                            Rate mop_accessor accessor_fast_accessor direct_hash
mop_accessor              5787/s           --                   -99%       -100%
accessor_fast_accessor  588235/s       10065%                     --        -76%
direct_hash            2500000/s       43100%                   325%          --

mop accessor is very very slow.

decide how attributes should behave

Attributes can be either local to each individual class in an inheritance hierarchy (Scala, Java, C#, Perl 6) or all merged together (Python, Ruby, Javascript, Perl 5). The first option is what is currently implemented, but we should make an explicit decision about which we actually want.

This has implications for a couple other design decisions:

  • Metaclass compat checking should not happen for overridden attributes if attributes are local to each class, but should if they are not.
  • Attribute conflict detection during role composition should not happen for overridden attributes if attributes are local to each class, but should if they are not.

How to weaken atribute reference.

Perl 5 has function which work to hash container.

For example, Scalar::Util weaken reduce hash reference count.

In one situation, object has cross-reference.

$foo->bar($bar);
$bar->foo($foo);

If this is hash based object, we do the following way.

use Scalar::Util;
weaken $bar->{foo};

In mop, how to weaken $bar->{foo}?

Map Moose idioms to MOP

20:40 stevan: has $foo = 10; # just literals
20:41 stevan: has $foo = do { die "WTF" }; # == required => 1
20:41 stevan: has $foo = do { ${^SELF}->foo }; # builder
20:41 stevan: has $foo = do { 100 }; # default
20:42 stevan: has $foo is lazy = do { ${^SELF}->foo }; # lazy + builder
20:42 stevan: has $foo is lazy = do { ${^SELF}->foo + 10 }; # lazy + default

and later:

22:07 stevan: I think lazy should be explicit
22:07 stevan: cause it is easier to optimize things without lazy
22:08 stevan: and if the  user asks for lazy, they get the performance penalty
22:15 doy: yeah

method keyword and subroutine signatures is parts of mop?

In mop prototype, multiple features is mixed.

class Point {
    has $x is rw;
    #1. method keyword ( automatically shift $self ) 
    #2. subroutine signatures
    method foo ($bar, $baz) {
        $self->x;
    }
}

Is method keyword part of mop? or independent feature?

Subroutine signature is independent feature, but current mop seem to implement subroutine signatures by itself.

These features will be separated into each parts in the future.

Is it good to prepare features separating?

shift @_

shift @_ is still required to remove $self

Should $obj->new act like ref($obj)->new

Per NY.pm discussion, defining a clear semantic for invoking 'new' on an object might lead to better consistency than leaving that behavior open for people do do other things with, e.g. using $obj->new to do a clone.

Subroutine method redefined

please close this issue if the behaviour is intended:

including

use mop;

in one of my modules results in a warning:
"Subroutine method redefined"

as there is a sub called "method" (which is used as a method)

How about simplification of attribute declaration

If attribute declaration is only limited to scalar, it will be simplified.

# Now
class Point  {
    has $!x is rw = 0;
    has $!y is rw = 0;

    method set_x($x) {
        $!x = $x;
    }
}

# Simplify or Alias for Scalar attribute
class Point  {
    has x is rw = 0;
    has y is rw = 0;

    method set_x($x) {
        $!x = $x;
    }
}

Twigils

It has been brought up that treating attributes entirely as lexical variables has some issues - it is a bit unclear to read in larger classes, and it can be confusing that declaring an attribute with the same name in a subclass actually creates an entirely new attribute (the way it works in Scala) rather than just overriding the behavior of the existing superclass attribute (the way it works in Moose, Ruby, Python, etc).

One solution to this could be to use twigils like Perl 6: has $.foo;, for instance. This would both provide visual differentiation and signal that these variables won't necessarily behave exactly like normal lexical variables.

Some things to note:

  • This won't be doable in the prototype, since we can't affect the parsing of variables.
  • Perl 6 actually works the other way: class Foo { has $.bar = 'BAR1'; method bar1 { $.bar } }; class Bar is Foo { has $.bar = 'BAR2'; method bar2 { $.bar } }; say Bar.new.bar1 ~ Bar.new.bar2 produces BAR2BAR2.

how important are ->isa checks on metaclasses?

Given this code:

class MetaFoo extends mop::class { }
class MetaBar extends mop::class { }
class Foo meta MetaFoo { }
class Bar extends Foo meta MetaBar { }

we end up with a situation where the linear isa of Bar's metaclass is ["mop::rebased::MetaBar", "MetaFoo", "mop::class"]. What this means is that mop::get_meta('Bar')->isa('MetaFoo') is true, but mop::get_meta('Bar')->isa('MetaBar') is false. This is fixable, but it would be a bit more effort than I'd like, since we don't have multiple inheritance. The question is, do we care about this? The equivalent code using metaroles does work:

role MetaFooRole { }
role MetaBarRole { }
class MetaFoo extends mop::class with MetaFooRole { }
class MetaBar extends mop::class with MetaBarRole { }
class Foo meta MetaFoo { }
class Bar extends Foo with MetaBar { }

Here, mop::get_meta('Bar')->does('MetaFooRole') and mop::get_meta('Bar')->does('MetaBarRole') are both true. Is this sufficient, or does this need to work with isa too?

Can't new object for my class from within a package

If I try to new an object from a mop class from inside a package I get a "Can't locate object method" error. I don't think I am doing anything wrong, here is a very trivial example:

iscah% more *
::::::::::::::
Foo.pm
::::::::::::::
use mop;

class Foo {
}

1;
::::::::::::::
foo.pl
::::::::::::::
package Bar;
use Foo;
my $foo = Foo->new;
iscah% perl foo.pl 
Can't locate object method "new" via package "Foo" (perhaps you forgot to load "Foo"?) at foo.pl line 3.

if I remove the package deceleration from foo.pl or if I move the use Foo above the package declaration then it works.

[wishlist]accessor is automatically created by default.

Accessor is needed for most attribute value. I proposal that accessor is automatically created by default.

For example. " is => 'rw' " is default trait.

class Point {
    has x;
    has y;
    has z;
    has no_need is no_accessor;
}

my $point = Point->new;
$point->x(1);
$point->y(2);
$point->z(3);

Syntax errors in methods cause misleading error messages

During parsing of method bodies, syntax errors in the body cause the Parse::Keyword::parse_block function to return a false value. The MOP consideres the result an unimplemented method. Example:

use mop;
class Foo {
  method glurg {
    my $what = "glurg" # missing semicolon
    print "$what\n";
  }
}

Output:

syntax error at test.pl line 5, near "print"
Required method(s) [glurg] are not allowed in Foo unless class is declared abstract at /some/path/mop/class.pm line 157.

This could be fixed by checking the return value for truth, and aborting compilation if neccessary. E.g. at syntax.pm, line 359 it could read:

my $code = parse_stuff_with_values($preamble, \&parse_block)
  or die "Error while parsing body for $type $name in $CURRENT_CLASS_NAME. Will not continue.\n";

I'm not sure if this is the correct way to address this, but it would aid debuggability.

__CLASS__ keyword

I comment about $class variable in commit page.
You suggest

__CLASS__

keyword to me.

I open it as issue.


yuki-kimoto

I think lower case $class is sometimes used by user.

For example.

my $class = caller;
$self crash user variable very little, but $class will sometime crash user variable.

stevan:
Yes, I have thought about that, but the most common usage of my $class = caller; is inside an import method, something that will not be relevant to the mop classes as they will never have exporters and any similar functionality will be done with mop events.

yuki-kimoto
I think also namespace, controller and action, for example. $class is maybe often used than you expect.
Is it enough Object and Class is accessed by $self?

stevan
We will likely convert $class to be

__CLASS__

instead. However, keep in mind that if you want to create your own $class that is not an issue, you will simply be overriding the $class that the MOP created.

failing tests on windows

cpanm [email protected]:stevan/p5-mop-redux.git

cpanm (App::cpanminus) 1.6005 on perl 5.016003 built for MSWin32-x64-multi-thread
Work directory is C:\Users\Andre/.cpanm/work/1375448068.3044
You have make C:\strawberry5.16\c\bin\dmake.exe
You have LWP 6.04
You have "C:\Program Files (x86)\Git\bin\tar.exe", "C:\Program Files (x86)\Git\bin\gzip.exe" and "C:\Program Files (x86)\Git\bin\bzip2.exe"
You have "C:\Program Files (x86)\Git\bin\unzip.exe"
Cloning [email protected]:stevan/p5-mop-redux.git
Cloning into 'C:/Users/Andre/AppData/Local/Temp/gbII6Urpwb'...
-> OK
--> Working on [email protected]:stevan/p5-mop-redux.git
Entering C:/Users/Andre/AppData/Local/Temp/gbII6Urpwb
Configuring C:/Users/Andre/AppData/Local/Temp/gbII6Urpwb
Running Makefile.PL
Writing Makefile for mop
Writing MYMETA.yml and MYMETA.json
-> OK
Checking dependencies from MYMETA.json ...
Checking if you have FindBin 0 ... Yes (1.51)
Checking if you have IO::Handle 0 ... Yes (1.33)
Checking if you have Test::Fatal 0 ... Yes (0.010)
Checking if you have Moose::Util::TypeConstraints 0 ... Yes (2.0604)
Checking if you have Test::More 0.88 ... Yes (0.98)
Checking if you have Test::Warn 0 ... Yes (0.24)
Checking if you have lib 0 ... Yes (0.63)
Checking if you have Path::Class 0 ... Yes (0.32)
Checking if you have Devel::PartialDump 0 ... Yes (0.15)
Checking if you have Moose 0 ... Yes (2.0604)
Checking if you have Scalar::Util 0 ... Yes (1.27)
Checking if you have MRO::Define 0 ... Yes (0.01)
Checking if you have Scope::Guard 0 ... Yes (0.20)
Checking if you have Sub::Exporter 0 ... Yes (0.985)
Checking if you have Module::Runtime 0 ... Yes (0.013)
Checking if you have Hash::Util::FieldHash 0 ... Yes (1.10)
Checking if you have warnings 0 ... Yes (1.13)
Checking if you have Parse::Keyword 0.04 ... Yes (0.06)
Checking if you have parent 0 ... Yes (0.225)
Checking if you have Package::Stash 0.27 ... Yes (0.34)
Checking if you have List::AllUtils 0 ... Yes (0.03)
Checking if you have overload 0 ... Yes (1.18)
Checking if you have Sub::Name 0 ... Yes (0.05)
Checking if you have B::Hooks::EndOfScope 0 ... Yes (0.12)
Checking if you have Carp 0 ... Yes (1.26)
Checking if you have strict 0 ... Yes (1.07)
Checking if you have Devel::GlobalDestruction 0 ... Yes (0.11)
Checking if you have Variable::Magic 0 ... Yes (0.52)
Checking if you have mro 0 ... Yes (1.09)
Building and testing p5-mop-redux-0.01
cp lib/mop.pm blib\lib\mop.pm
cp lib/mop/method.pm blib\lib\mop\method.pm
cp lib/mop/role.pm blib\lib\mop\role.pm
cp lib/mop/observable.pm blib\lib\mop\observable.pm
cp lib/mop/manual/tutorials/moose_to_mop.pod blib\lib\mop\manual\tutorials\moose_to_mop.pod
cp lib/mop/object.pm blib\lib\mop\object.pm
cp lib/mop/attribute.pm blib\lib\mop\attribute.pm
cp lib/mop/manual/intro.pod blib\lib\mop\manual\intro.pod
cp lib/mop/traits.pm blib\lib\mop\traits.pm
cp lib/mop/util.pm blib\lib\mop\util.pm
cp lib/mop/internals/mro.pm blib\lib\mop\internals\mro.pm
cp lib/mop/class.pm blib\lib\mop\class.pm
cp lib/mop/internals/syntax.pm blib\lib\mop\internals\syntax.pm
cp lib/mop/manual/details/classes.pod blib\lib\mop\manual\details\classes.pod
C:\strawberry5.16\perl\bin\perl.exe "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib\lib', 'blib\arch')" t/*.t t/*/*.t t/300-ext/*/*.t
t/000-bootstrap.t ...................................................... ok
t/001-examples/001-point.t ............................................. ok
t/001-examples/002-bank-account.t ...................................... ok
t/001-examples/003-binary-tree.t ....................................... ok
t/001-examples/004-linked-list.t ....................................... ok

#   Failed test '... got the exception'
#   at t/001-examples/005-throwable.t line 54.
#                   'Trace begun at t\001-examples\005-throwable.t line 37
# main::bar at t\001-examples\005-throwable.t line 39
# eval {...} at t\001-examples\005-throwable.t line 39
# '
#     doesn't match '(?^:^Trace begun at t\/001\-examples\/005\-throwable\.t line 37
# main::bar at t\/001\-examples\/005\-throwable\.t line 39
# eval {\.\.\.} at t\/001\-examples\/005\-throwable\.t line 39
# )'
# Looks like you failed 1 test of 4.
t/001-examples/005-throwable.t ......................................... 
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/4 subtests 
t/001-examples/006-logger.t ............................................ ok
t/001-examples/007-currency.t .......................................... ok
t/010-basics/000-basic.t ............................................... ok
t/010-basics/001-new.t ................................................. ok
t/010-basics/002-new-w-attributes.t .................................... ok
t/010-basics/003-BUILD.t ............................................... ok
t/010-basics/004-DEMOLISH.t ............................................ ok
t/010-basics/005-attribute-override.t .................................. ok
t/010-basics/006-next-method.t ......................................... ok
t/010-basics/007-class-methods.t ....................................... ok
t/010-basics/010-packages.t ............................................ ok
t/010-basics/011-packages-w-exports.t .................................. ok
t/010-basics/012-fully-qualified-class-name.t .......................... ok
t/010-basics/013-nested-packages.t ..................................... ok
t/010-basics/014-loading-from-disk.t ................................... ok
t/010-basics/015-inheritance-loading-from-disk.t ....................... ok
t/010-basics/016-return-true-loading-from-disk.t ....................... ok
t/010-basics/020-simple-attributes.t ................................... ok
t/010-basics/021-attributes-w-defaults.t ............................... ok
t/010-basics/022-attributes-w-lazy-defaults.t .......................... ok
t/010-basics/023-attribute-w-lazy-accessor.t ........................... ok
t/010-basics/024-attribute-w-complex-defaults.t ........................ ok
t/010-basics/025-attributes-w-lazy-complex-defaults.t .................. ok
t/010-basics/026-complex-attributes.t .................................. ok
t/010-basics/027-multi-complex-attributes.t ............................ ok
t/010-basics/030-abstract-classes.t .................................... ok
t/010-basics/031-arbitrary-abstract-classes.t .......................... ok
t/030-roles/001-basic.t ................................................ ok
t/030-roles/002-compose-into-role.t .................................... ok
t/030-roles/003-multiple-role-compose.t ................................ ok
t/030-roles/004-DOES.t ................................................. ok
t/030-roles/010-role-to-abstract-class.t ............................... ok
t/030-roles/020-attribute-conflict.t ................................... ok
t/030-roles/025-method-conflict.t ...................................... ok
t/030-roles/030-around-in-roles.t ...................................... ok
t/050-non-mop-integration/001-inherit-from-non-mop.t ................... ok
_expand_glob called on stash slot with expanded glob at C:/strawberry5.16/perl/vendor/lib/Class/MOP/Package.pm line 243.
t/050-non-mop-integration/002-more-non-mop.t ........................... 
Dubious, test returned 255 (wstat 65280, 0xff00)
No subtests run 
t/050-non-mop-integration/003-attributes-in-non-mop-inherited-class.t .. ok
t/050-non-mop-integration/010-reverse-integration.t .................... ok
t/100-internals/001-instance.t ......................................... ok
t/110-oddities/001-syntax-error.t ...................................... ok
t/110-oddities/002-lexical-override-attribute.t ........................ ok
t/110-oddities/003-metadata-errors.t ................................... ok
t/110-oddities/004-returning-lexicals.t ................................ ok
t/110-oddities/005-naming-conflict.t ................................... ok
t/110-oddities/006-order-of-declaration.t .............................. ok
t/110-oddities/007-sub-vs-method.t ..................................... ok
t/110-oddities/008-method-method.t ..................................... ok
t/110-oddities/009-method-method-from-disk.t ........................... ok
t/110-oddities/010-recursive-self.t .................................... ok
t/110-oddities/011-universal-methods.t ................................. ok
t/110-oddities/012-inc-hash.t .......................................... ok
t/110-oddities/013-overriding-attribute-w-param.t ...................... ok
t/110-oddities/014-classes-with-namespaces.t ........................... ok
t/110-oddities/015-semicolons-separate.t ............................... ok
t/120-bugs/001-plack-parser-bug.t ...................................... ok
t/120-bugs/016-github.t ................................................ ok
t/150-parser-tests/001-basic.t ......................................... ok
t/150-parser-tests/002-basic.t ......................................... ok
t/150-parser-tests/003-basic.t ......................................... ok
t/200-meta/001-basic.t ................................................. ok
t/200-meta/002-meta-w-data.t ........................................... ok
t/200-meta/003-localized-vars-in-class.t ............................... ok
t/200-meta/004-localized-vars-in-roles.t ............................... ok
t/200-meta/005-associated-class.t ...................................... ok
t/200-meta/010-extension.t ............................................. ok
t/200-meta/011-more-extensions.t ....................................... ok
t/200-meta/012-attr-metaclass.t ........................................ ok
t/200-meta/020-create-instance-w-meta.t ................................ ok
t/300-ext/Option/000-load.t ............................................ ok
t/300-ext/Test-BuilderX/001-load.t ..................................... ok
t/300-ext/Test-BuilderX/010-Test_Builder.t ............................. ok
t/300-ext/Test-BuilderX/020-Test_Builder_Test.t ........................ ok
t/400-traits/001-traits.t .............................................. ok
t/400-traits/002-class-trait.t ......................................... ok
t/400-traits/003-type-trait.t .......................................... ok
t/400-traits/004-weaken-trait.t ........................................ ok
t/400-traits/005-method-traits.t ....................................... ok
t/400-traits/006-overload-trait.t ...................................... ok
t/400-traits/007-built-by-trait.t ...................................... ok
t/400-traits/008-lazy-trait.t .......................................... ok
t/400-traits/020-moose-traits.t ........................................ ok

Test Summary Report
-------------------
t/001-examples/005-throwable.t                                       (Wstat: 256 Tests: 4 Failed: 1)
  Failed test:  4
  Non-zero exit status: 1
t/050-non-mop-integration/002-more-non-mop.t                         (Wstat: 65280 Tests: 0 Failed: 0)
  Non-zero exit status: 255
  Parse errors: No plan found in TAP output
Files=88, Tests=892, 20 wallclock secs ( 0.36 usr +  0.11 sys =  0.47 CPU)
Result: FAIL
Failed 2/88 test programs. 1/892 subtests failed.
dmake.exe:  Error code 255, while making 'test_dynamic'
-> FAIL Installing [email protected]:stevan/p5-mop-redux.git failed. See C:\Users\Andre\.cpanm\build.log for details.

Get rid of find_or_create_meta

This is probably not a good idea:

21:03 stevan: doy: I am also not sure about this find_or_create_metaclass
21:03 doy: yeah, i wasn't sure about that either
21:03 stevan: I dont see a reason to inflate a meta out of a non-meta
21:03 doy: it's how moose handles things
21:03 stevan: yeah, fuck Moose
21:03 doy: but it is a bit questionable
21:03 stevan: do you actually use it>
21:03 doy: yeah
21:04 doy: some non-mop inheritance stuff will break without it currently
21:04 doy: but i'd be open to alternative ways to accomplish that

method conflicts during role application aren't handled properly

See t/030-roles/026-multiple-method-conflict.t. This isn't quite straightforward to fix:

<doy> hmmm, we may need to rethink how role composition works
<doy> role R1 { method foo {} }; role R2 { method foo {} }; role R3 { method foo {} }; class C1 with R1, R2, R3 {} # this should error
<doy> role R1 { method foo; }; role R2 { method foo; }; role R3 { method foo {} }; class C1 with R1, R2, R3 {} # this should not error
<doy> but after R1 and R2 have been composed into the composite role, the composite roles at that point are identical
<doy> and so they will have to do identical things after composing in R3
<doy> i think $role->compose_into may be the wrong abstraction
<doy> $class->consume may work out better

Remove ${^SELF}

15:50 perigrin: if ${^SELF} points to the current instance then has $self; isn't bad enough to warrent a compiletime failure. You haven't irrevocably shot yourself in the foot.
15:51 perigrin: you are an idiot, but one that can survive with a walking cast.
15:53 doy: i don't know that ${^SELF} is necessarily a good idea though
15:54 stevan: doy: it was mostly there for when you inject a method into the class, but actually you can pull $self off @_ then, so it isn't as necessary
15:57 stevan: doy: I will make a ticket to remove it, we can revisit it later
15:57 doy: okay

Issues 'require'-ing a class

Something like

class MyClass { 
    method load_plugin { eval "require $plugin_class" }  
}

doesn't work because of the same curstash_name thing :/

Constructor performance mop(Jul 21, 2013) vs Class::Accessor::Fast

use mop;
use Data::Dumper;

class mopClass {
  has $foo is rw;
  has $bar is rw;
  has $baz is rw;
}


package ClassAccessorFastClass;
use strict;
use warnings;
use base 'Class::Accessor::Fast';

__PACKAGE__->mk_accessors('foo', 'bar', 'baz');

package main;

use Benchmark qw/timethese cmpthese/;

my $result = timethese(10000, {
  # mop accessor
  mop_new => sub {
    my $mop_obj = mopClass->new;
  },
  # Class::Accessor::Fast accessor
  accessor_fast_new => sub {
    my $class_accessor_fast_obj = ClassAccessorFastClass->new;
  }
});

cmpthese $result;

result

Benchmark: timing 10000 iterations of accessor_fast_new, mop_new...
accessor_fast_new:  0 wallclock secs ( 0.02 usr +  0.00 sys =  0.02 CPU) @ 500000.00/s (n=10000)
            (warning: too few iterations for a reliable count)
   mop_new:  4 wallclock secs ( 4.01 usr +  0.01 sys =  4.02 CPU) @ 2487.56/s (n=10000)
                      Rate           mop_new accessor_fast_new
mop_new             2488/s                --             -100%
accessor_fast_new 500000/s            20000%                --

mop constructor is very slow.

Alias for accessor

I want to define accessor easily. In Perl6, $.x create accessor, $!x create only attribute.

# Perl6
class MyClass {
   has $.x; # create attribute and accessor
   has $!x; # create only attribute
}

My proposal:

class MyClass {
   has x; # create attribute and accessor
   has $!x; # create only attribute
}

x is associated with method, and $!x is associated with variable.
Generally speaking, many accessors are created. It is good to provide the way to create accessor easily.

__PACKAGE__

use strict;
use warnings;

use Test::More;
use Test::Fatal;

use mop;

class Foo {
    method test () {
        __PACKAGE__->test2;
    }

    method test2 () {
        print "Hello World";
    }


}

Foo->test;

1;

is PACKAGE expected to work? Is there something similar such as CLASS

Write test for Object methods on Role metaobject

I left a comment in 0dc09c2 about this, originally mop::role did not inherit from mop::object, but now it does, we need to test all the methods in mop::object (does, DOES, isa, etc.) to make sure they behave sanely on Role metaobject instances.

need to document the difference between `new` and `BUILD`

In particular, BUILD is called by new_instance, so it will also be called when you clone an object, but an overridden new method will not. Overriding new should basically only be done to provide a different method signature, any actual behavioral changes should probably go in BUILD.

Document why ```has``` only supports scalars

17:21 stevan: doy: actually, thnking about it
17:21 stevan: has should work just like my
17:21 stevan: my $foo;
17:21 stevan: $foo is implictly undef
17:21 doy: right
17:21 stevan: but that means that if we support has @foo and has %foo
17:21 doy: that's what i was thinking
17:21 stevan: then those need to init [] and {} behind the scences too
17:21 doy: sure
17:23 doy: it'll mean that you can only use lazy on scalars
17:23 doy: but i don't think that's too unreasonable
17:24 stevan: well the auto [] and {} should be lazy anyway
17:24 stevan: but actually
17:24 stevan: no
17:24 stevan: this hsould work
17:24 stevan: has @foo is lazy = [ 1, 2, 3 ];
17:25 stevan: or rather
17:25 stevan: has @foo is lazy = do { [ 1, 2, 3 ] };
17:25 stevan: or perhaps
17:25 doy: no more do blocks!
17:25 stevan: has @foo is lazy = do { ( 1, 2, 3 ) };
17:25 doy: (:
17:25 stevan: haha
17:25 stevan: has @foo is lazy = ( 1, 2, 3 );
17:25 stevan: that should work then
17:25 doy: yeah
17:25 stevan: as should
17:25 doy: that last one
17:25 stevan: has @foo = ( 1, 2, 3 );
17:25 doy: yeah
17:29 doy: hmmm
17:29 doy: i'm not sure how much sense that makes though
17:29 tobyink: if lazy only worked on scalars, that wouldn't be so awful. Already the initialization of "state" variables only works on scalars.
17:29 doy: for arrays and hashes to have a special "unset" state, but not scalars
17:31 doy: has @foo = (1, 2, 3); -> has $foo is lazy = [1, 2, 3];
17:31 doy: i mean, arrays and hashes are already going to have to be treated differently in other circumstances anyway
17:32 doy: they can't use accessors the same way that scalars do
17:32 doy: $self->foo(@things) is a broken way to do things, for multiple reasons
17:36 stevan: doy: yes, true, we went over this before
17:36 stevan: has @foo = [];  just is odd
17:36 stevan: especially since you can do
17:36 stevan: method foo { @foo = @_ }
17:36 doy: really though, just not implementing "has @foo" and "has %foo" is also a valid option
17:36 stevan: right
17:37 stevan: meaning, without allowing initialization
17:37 stevan: I am not sure that is okay
17:37 doy: hmmm?
17:37 doy: no, i mean not implementing them at all
17:37 stevan: oh
17:37 stevan: sorry, didnt see the not
17:37 stevan: yeah, maybe
17:38 doy: i mean, the only reason it works in perl 6 is because they made everything a reference
17:38 stevan: yeah
17:38 stevan: and
17:39 stevan: method add_foo ($f) { push @$foo => $f }
17:39 stevan: is not that bad
17:39 stevan: and actualy
17:39 stevan: method add_foo ($f) { push $foo => $f }
17:39 stevan: works now too
17:39 doy: right
17:39 doy: (don't use the second form)
17:39 stevan: yeah, agreed
17:39 doy: but yeah

metaclass compatibility for attributes and methods

This involves two separate issues. First, the classes in attribute_class and method_class need to be compatible with the superclass versions, so that a class metaclass can define those and be able to assume that every attribute or method will conform to that API, even in subclasses. Second, overriding an attribute or method should make the metaclass of that specific attribute or method compatible with the metaclass of the attribute or method that it is overriding.

Trap class method attribute access

If a method is called as a class method, but the method tries to access instance data, we should trap it and throw an exception. I suspect this can be handled in the Variable::Magic wizard in the syntax module.

Top level classes issue

So the issue is this:

package Foo;

class Foo {}

Actually creates class Foo::Foo, which may not be what is wanted. The proposed solution is to do:

package Foo;

class ::Foo {}

to indicate that we want a top-level class. This maps to how subs behave, so should be easy enough to understand.

Previously this was used as the solution:

package main;

class Foo {}

but this breaks down if you want to import functions that your class can use, such as:

package main;
use Path::Class qw[ file ];

class Foo {}

which then imported the file function into the main namespace, which is (more often then not) undesirable.

Do we have to say is?

When I run this code

#!/usr/bin/env perl

use v5.18;
use warnings;
use mop;

class myBaseClass {
    has $!myID;
    has $!myName;
    method doMsg ($m) { say $m }
}

class myDerivedClass extends myBaseClass {
    method hello { say __LINE__." Hello from myDerivedClass" }
}

my $v= myDerivedClass->new(myID => time , myName => 'DC');
$v->hello;
$v->doMsg($v->myName ." Very nice! How much RAM is Eclipse using?");

I get an error

$ ./usemop.pl
14 Hello from myDerivedClass
Could not find myName in myDerivedClass=SCALAR(0x1b1bc48) at /home/tim/.plenv/versions/5.18.1/lib/perl5/site_perl/5.18.1/mop/internals/mro.pm line 141.

But if I change line 9 to

    has $!myName is ro;

it works as expected

$ ./usemop.pl
14 Hello from myDerivedClass
DC Very nice! How much RAM is Eclipse using?

Twigil exclamation mark !

I think twigil exclamation mark ! is a little difficult to read.

In Perl, ! mean "deny". And ! is often used.

if (!$!title) {

}

What about other mark?

if (!$:title) {

}

Meta Object Protocol is misleading name?

I think all of mop component(class name, attribute name, attribute option, method name, role) is belong to class, not object.

Is it enough that Object know only data and class name?
Are objects needed to be managed from global meta position?

Question about Object data strage.

Now, attribute value is stored into inside-out object.
How about using simple hash reference.

  1. performance reason, inside-out object is a little slow.
  2. Current Perl Convention. Perl does not impose constraints to user.
  3. Simplicity. inside-out object is a little tricky, hash reference is simple.
  4. It is easy to use weaken function.
  5. User can see object internal by Data::Dumper. Normal object can be dumped by Data::Dumper,
    but, mop object can't be dumped. this is not convenient for user.

custom attribute handling via new

has $one;
has $two;
has $three;

TestClass->new(1, 2, 3);

submethod BUILDARGS (@params) {
   $one   => $params[0],
   $two   => $params[1],
   $three => $params[2]
}

Add special NIL constant for slots which are not yet initialized

this is to allow people to tell the difference between a slot set to undef and a slot that has not yet been populated.

14:11 phaylon: I was just wondering, would there be a way for me to know whether an attribute has a value or not without a trait giving me a method?
14:21 tobyink: phaylon: mop::attribute has a `has_data_in_slot_for` method.
14:21 perigrin: phaylon: mop::util::find_meta($meta)->get_attribute('$attribute')->has_data_in_slot_for($meta, ${^SELF});
14:22 perigrin: sorry s/$meta,//
14:22 tobyink: Also, prefer s/mop::util::find_meta/mop::get_meta/
14:23 tobyink: Oh, and it's mop::util::find_meta($classname) anyway.
14:23 perigrin: I'm just copying from something doy pasted a few days ago
14:23 perigrin: http://paste.tozt.net/2013-07-23xGthHyQ7-test.pl
14:23 perigrin: I do that well :)
14:24 perigrin: tobyink: find_meta can take either a classname or a blessed instance
14:25 perigrin: it passes the first argument to get_stash_for() which does my $class = ref($_[0]) || $_[0];
14:25 tobyink: Yes, mop::util::find_meta should work, but mop::get_meta is the public API. It e.g. throws a sensible error message instead of just returning undef.
14:25 tobyink: perigrin: yes, but the blessed instance is an instance of the class, it's not the metaclass.
14:26 perigrin: mop::get_meta(${^SELF})->get_attribute('$attribute')->has_data_in_slot_for(${^SELF});
14:27 perigrin: phaylon: that's I think the properly pained bikeshed.
14:32 phaylon: well, that's kinda wordy, but alright :)
14:33 phaylon: I don't really have a use for it anyway, it was just a thought :)
14:34 leedo: that seems like something you wouldn't need the mop to find out
14:36 perigrin: leedo: one could hope that "defined $attribute" might work but the instances in p5-mop are intentionally opaque
14:36 perigrin: so exists $self->{attr} doesn't dwim.
14:37 leedo: right, i was just thinking the former would work
14:38 perigrin: leedo: might, but with the current setup in the prototype, I know the mop version will :)
14:38 stevan: defined $attribute will work, inside a method
14:38 stevan: leedo: perigrin: ^
14:38 stevan: outside a method, nope
14:38 stevan: you need the mop
14:38 perigrin nods
14:38 stevan: but if you did exists $myobj->{foo} outside a method, you should be shot
14:38 phaylon: well, one argument against defined($attr) is that if you don't have a type constraint on it, your public api will include undef as no-value
14:38 tobyink: defined $attribute works, but doesn't distinguish between exists and ==undef.
14:38 stevan: phaylon: that is true
14:39 stevan: on both accounts
14:39 perigrin: time to override CORE::exists
14:40 phaylon: not to mention the people who will just do if ($attr) if they expect an object, and then 0, '' & Co will also become non-values
14:40 perigrin hides
14:40 tobyink: It would be awesome if exists($scalar) could be hijacked.
14:40 stevan: it might be able to be
14:40 phaylon: in my toy-thingy I was thinking about a boolean twigil like $? for existance vs $. for access, so you never have to type more to be correct
14:40 stevan: actually, come to think of it
14:41 stevan: the variables are created in the method preamble
14:41 stevan: and like all scalars they are undef
14:41 stevan: so, they are always undef
14:41 tobyink: phaylon: tricky to parse
14:41 stevan: if you explictly want to check defined in storage, that is different
14:41 phaylon: tobyink: in perl, yes :)
14:41 stevan: phaylon: yeah, I have been told twigils are a LOT of work
14:42 stevan really needs to write a Moose->mop manual
14:42 stevan: but right now, I need to shower
14:42 phaylon: well, in perl 5, not to offend someone :)
14:43 phaylon: one usecase I could think of is dumb serialization of data, where I'd currently do e.g. { $self->_has_foo ? (foo => $self->foo) : () }
14:44 stevan: yeah I gotta do some thinking
14:45 stevan: cause, well, I think I caused trouble with Moose
14:45 phaylon: maybe just propose to p5p to introduce a new value: notevenundef
14:45 stevan: which is why people like MooseX::UndefTOlerant
14:45 stevan: phaylon: I think scalars have some weird stuff that makes them init to undef
14:45 stevan: we hit this crap in Package::Stash
14:45 phaylon: ooh, $attr < undef # bam! now everyone hates you!
14:45 stevan: its built into the language
14:46 phaylon: well, I was kinda expecting this to be more of a theoretical problem, in practices you'd probably just use some trait of cpan in the worst case
14:46 phaylon: s/of/off/
14:47 stevan: wait a second, I am stupid
14:47 phaylon: just noticed I started saying "well" a lot again. probably because of the heat
14:48 stevan: so I control the value in the variable
14:48 stevan: it is only undef if there is nothing in the slot cause of this
14:48 stevan: https://github.com/stevan/p5-mop-redux/blob/master/lib/mop/attribute.pm#L82
14:49 stevan: no reason that can't be
14:49 stevan: my $val = ${ $self->storage->{ $instance } || \$mop::NIL };
14:49 stevan: then people could just do
14:49 stevan: if ( $attribute == NIL ) { ... }
14:49 stevan: where NIL is an exported constant from mop.pm
14:51 phaylon: seems a bit unaligned with how undef is handled. maybe if (nil $attr)? can the new keyword stuff do non-function-call inlining to make it quick? I kinda forgot
14:51 stevan: phaylon: maybe
14:51 stevan: but speed is not an issue now
14:51 stevan: for now it could be a sub
14:52 phaylon: stevan: would this also enable an extension to (for example) die if you try to use a nil value? don't see anything speaking against that, but don't know the internals

update of wrong (or no update of) instance variable

use strict;
use warnings;
use mop;


class Foo {
    has $test;

    method set_test {
        $test = $_[0];
        $self;
    }
}


class Bar (extends => 'Foo') {
    has $test;

    method get_test {
        $test
    }
}

warn Bar->new->set_test(1)->get_test;

would expect 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.