Returning a 'raw' scalar container from AT-POS method (rather than a Proxy instance) in a class that 'does' Positional?

Assuming you do not want accessors for "slot_1" and "slot_2", and if I understand the question correctly, this would be my implementation. I wouldn't call it a Test class, as that would interfere with the Test class that is used for testing.

class Foo {
    has @elements = 24, 12;

    method AT-POS(Int:D $pos) is raw {
        @elements[$pos % 2]
    }
}

my $f = Foo.new;
say $f[2];  # 24
say $f[5];  # 12

$f[2] = 666;
say $f[4];  # 666

Note that the defaults in the array have changed order, that's to keep the arithmetic in AT-POS simple.

Also note the is raw in the definition of the AT-POS method: it will ensure that no de-containerization will take place when returning a value. This allows you to just assign to whatever $f[2] returns.

Hope this made sense!

Also: the Array::Agnostic module may be of interest for you, to use directly, or to use as a source of inspiration.


First off if you aren't going to use an attribute outside of the object, there isn't a reason to declare them as public, and especially not rw.

class Foo {
    has $!odd = 12;
    has $!even = 24;

    …
}

You can also directly return a Scalar container from a method. You should declare the method as rw or raw. (raw doesn't guarantee that it is writable.)

class Foo {
    has $!odd = 12;
    has $!even = 24;

    method AT-POS(\position) is rw {
        position % 2 ?? $!odd !! $!even
    }
}

# we actually get the Scalar container given to us
say Foo.new[10].VAR.name; # $!even

Note that even if you declare the attributes as public they still have a private name. The private attribute is always rw even if it isn't publicly declared as rw.

class Foo {
    has $.odd = 12;
    has $.even = 24;

    method AT-POS(\position) is rw {
        position % 2 ?? $!odd !! $!even
    }
}

If you are going to use a Proxy, I would consider moving the common code outside of it.

class Foo {
    has $.odd = 12;
    has $.even = 24;

    method AT-POS(\position) is rw {
        # no need to write this twice
        my $alias := (position % 2 ?? $!odd !! $!even);

        Proxy.new:
            FETCH => method () { $alias },
            STORE => method ($new-value) { $alias = $new-value }
    }
}

Of course the ?? !! code is a core feature of this module, so it would make sense to put it into a single method so that you don't end up with duplicate code all over your class. In this case I made it a private method.

class Foo {
    has $.odd = 12;
    has $.even = 24;

    # has to be either `raw` or `rw`
    # it is debatable of which is better here
    method !attr(\position) is raw {
        position % 2 ?? $!odd !! $!even
    }

    method AT-POS(\position) is rw {
        my $alias := self!attr(position);

        Proxy.new:
            FETCH => -> $ { $alias },
            STORE => -> $, $new-value { $alias = $new-value }
    }
}

Again, not much reason to use a Proxy.

class Foo {
    has $.odd = 12;
    has $.even = 24;

    method !attr(\position) is raw {
        position % 2 ?? $!odd !! $!even
    }

    method AT-POS(\position) is rw {
        self!attr(position);
    }
}

Instead of ?? !! you could use an indexing operation.

method !attr(\position) is raw {
    ($!even,$!odd)[position % 2]
}

Which would allow for a ternary data structure.

method !attr(\position) is raw {
    ($!mod0,$!mod1,$!mod2)[position % 3]
}

There was no need to write the if statement that you did as Raku usually passes Scalar containers around instead of the value.

(position % 2 ?? $t.slot_1 !! $t.slot_2) = $v;

Tags:

Raku