Skip to content

Commit

Permalink
Allow sub-classing of Proxy objects
Browse files Browse the repository at this point in the history
Inspired by:

  https://stackoverflow.com/questions/58055309/a-scalar-with-memory-or-how-to-correctly-tie

This allows one to say:

    class Foo is Proxy {
    }

and implement additional functionality to the Proxy object, like keeping
track which values a variable has had (from the SO question).

With much help from Jonathan Worthington.
  • Loading branch information
lizmat committed Sep 24, 2019
1 parent 554f91e commit 4a76778
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/Perl6/Metamodel/ClassHOW.nqp
Expand Up @@ -21,6 +21,7 @@ class Perl6::Metamodel::ClassHOW
does Perl6::Metamodel::BoolificationProtocol
does Perl6::Metamodel::REPRComposeProtocol
does Perl6::Metamodel::InvocationProtocol
does Perl6::Metamodel::ContainerSpecProtocol
does Perl6::Metamodel::Finalization
does Perl6::Metamodel::Concretization
{
Expand Down Expand Up @@ -220,6 +221,7 @@ class Perl6::Metamodel::ClassHOW
self.publish_type_cache($obj);
self.publish_method_cache($obj);
self.publish_boolification_spec($obj);
self.publish_container_spec($obj);

# Compose the meta-methods.
self.compose_meta_methods($obj);
Expand Down
34 changes: 34 additions & 0 deletions src/Perl6/Metamodel/ContainerSpecProtocol.nqp
@@ -0,0 +1,34 @@
role Perl6::Metamodel::ContainerSpecProtocol {
has $!code_pair;

method get_container_spec($obj) {
$!code_pair
}

method set_container_spec($obj, $code_pair) {
$!code_pair := $code_pair;
}

method publish_container_spec($obj) {
# If we have a container specification here, install that
if $!code_pair {
nqp::setcontspec($obj, 'code_pair', $!code_pair);
$obj.HOW.compose_repr($obj);
}

# look in the parents for any if none here
else {
for self.mro($obj) -> $class {
if nqp::can($class.HOW, 'get_container_spec') {
my $code_pair := $class.HOW.get_container_spec($class);
if $code_pair {
$!code_pair := $code_pair;
nqp::setcontspec($obj, 'code_pair', $!code_pair);
$obj.HOW.compose_repr($obj);
last;
}
}
}
}
}
}
7 changes: 3 additions & 4 deletions src/Perl6/bootstrap.c/BOOTSTRAP.nqp
Expand Up @@ -1749,17 +1749,16 @@ BEGIN {
nqp::getattr($cont, Proxy, '&!STORE')($var, $val)
})));
Proxy.HOW.add_method(Proxy, 'new', nqp::getstaticcode(sub ($type, :$FETCH!, :$STORE!) {
my $cont := nqp::create(Proxy);
my $cont := nqp::create($type);
nqp::bindattr($cont, Proxy, '&!FETCH', $FETCH);
nqp::bindattr($cont, Proxy, '&!STORE', $STORE);
$cont
}));
Proxy.HOW.compose(Proxy);
nqp::setcontspec(Proxy, 'code_pair', nqp::hash(
Proxy.HOW.set_container_spec(Proxy, nqp::hash(
'fetch', $PROXY_FETCH,
'store', $PROXY_STORE
));
Proxy.HOW.compose_repr(Proxy);
Proxy.HOW.compose(Proxy);

# Helper for creating a scalar attribute. Sets it up as a real Perl 6
# Attribute instance, complete with container descriptor and optional
Expand Down
1 change: 1 addition & 0 deletions tools/templates/common_metamodel_sources
Expand Up @@ -8,6 +8,7 @@ src/Perl6/Metamodel/LanguageRevision.nqp
src/Perl6/Metamodel/TypePretense.nqp
src/Perl6/Metamodel/MethodDelegation.nqp
src/Perl6/Metamodel/BoolificationProtocol.nqp
src/Perl6/Metamodel/ContainerSpecProtocol.nqp
src/Perl6/Metamodel/PackageHOW.nqp
src/Perl6/Metamodel/ModuleHOW.nqp
src/Perl6/Metamodel/GenericHOW.nqp
Expand Down

0 comments on commit 4a76778

Please sign in to comment.