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

I'm attempting to implement a class that 'does' Positional that also allows me to update its values by assigning to the result returned by the AT-POS method. Eventually, I was able to concoct the following class that works as intended:
class Test does Positional
{
has $.slot_1 is rw = 12;
has $.slot_2 is rw = 24;
method AT-POS(\position)
{
my $t = self;
return-rw Proxy.new:
FETCH => method ()
{
position % 2 ?? $t.slot_1 !! $t.slot_2
},
STORE => method ($v)
{
if position % 2
{
$t.slot_1 = $v
}
else
{
$t.slot_2 = $v
}
}
}
}
my $test = Test.new;
die unless $test[2] == 24;
die unless $test[5] == 12;
$test[7] = 120;
die unless $test[2] == 24;
die unless $test[5] == 120;
$test[10] = 240;
die unless $test[2] == 240;
die unless $test[5] == 120;
Would it be possible to somehow (and: simply) return the container bound to $!slot_1 (or $!slot_2) inside the Test class implementation?
Before I discovered the use of Proxy instances I attempted to return (and return-rw) the result of expression position % 2 ?? $!slot_1.VAR !! $!slot_2.VAR, because I'm under the impression that the VAR method gives me access to the underlying container, in the hope that I can simply return it. That didn't really work, and I do not understand why yet: I suspect it somehow gets coerced back to a value somehow?
So in other words: is it possible to simplify my AT-POS implementation in this particular situation?
Thanks,
Regards,
Raymond.

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;

Related

Error "Out of segment space" in VMEmulator cause by a getter mwthod in Jack

I am doing a project for nand2tetris. We write a program in Jack and test it on VMEmulator. The class looks like this:
class List {
field int data;
field List next;
/* Creates a new List object. */
constructor List new(int car, List cdr) {
let data = car;
let next = cdr;
return this;
}
/* Disposes this List by recursively disposing its tail. */
method void dispose() {
if (~(next = null)) {
do next.dispose();
}
// Use an OS routine to recycle the memory held by this object.
do Memory.deAlloc(this);
return;
}
/* Prints the list*/
method void print() {
do Output.printString(" -> ");
do Output.printInt(data);
if (~(next = null)) {
do next.print();
}
return;
}
/* Inserts the argument in the right position of the list (ascending order)*/
method void insertInOrder(int ins){
var List prev, curr, insert;
let prev = this;
let curr = prev.getnext();
while (ins > prev.getdata()){
if (ins < curr.getdata()){
let insert = List.new(ins, curr);
do prev.setnext(insert);
}
else{
let prev = prev.getnext();
let curr = prev.getnext();
}
}
return;
}
/* Searches the argument in the list, if found, it returns the corresponding List object*/
method List find(int toFind){
var List temp;
var List equal;
var boolean found;
let temp = this;
let found = false;
while (~(next = null)){
if(toFind = temp.getdata()){
let equal = temp;
let found = true;
}
let temp = temp.getnext();
}
if (found){
return equal;
}
else{
return null;
}
}
method List getnext(){
return next;
}
method void setnext(List object){
let next = object;
return;
}
method int getdata(){
return data;
}
}
It has one private variable data and a pointer next. So I wrote getter and setter method to return those values. Other methods are fine only the getdata()method is incorrect. When it runs through the VMEmulator, it shows the error Out of segment space in List.getdata.3. This shows in the VMEmulator.
0function List.getdata0
1push argument0
2pop pointer0
3push this 0
4return
the error is at the 4th line return. When I change the Jack code, the same error is still at the 4th line.
What exactly is the problem in my getter method?
When you run a VM program on the VMEmulator you must first manually set the pointers to the various segments, otherwise you may get an "Out of segment space" error.
To understand the necessary settings, look at what the corresponding .tst file does. An alternative method is to insert the proposed code inside a function, since the function call automatically makes this type of setting.
You can get this error when you try to access member data of an object which is not constructed. Could it be that the List cdr in the constructor was not properly constructed?

Multimethod for Proxy

Is it possible to use multidispatch for the store method when using a Proxy? In the following minimal example, the code is called when storing an Int
my $foo := do {
my $bar = 1;
Proxy.new:
:FETCH( method { return $bar} ),
:STORE( method (Int $i) { $bar = $i } )
}
say $foo; # 1
$foo = 2;
say $foo; # 2
$foo = "3"; # error, need to pass an Int
But I'd like to handle the STORE differently if given, say, a Str. The work around I've found (other than doing a mega method with given/where is to create a multi sub inside of a block, and return the sub (because a multi method can't be referred to with &foo) with an dummy first parameter:
my $foo := do {
my $bar = 1;
Proxy.new:
:FETCH( method { return $bar} ),
:STORE(
do {
multi sub xyzzy ($, Int $i) { $bar = $i }
multi sub xyzzy ($, Str $i) { $bar = +$i + 1}
&xyzzy
}
)
}
say $foo; # 1
$foo = 2;
say $foo; # 2
$foo = "3";
say $foo; # 4
Is there a better way to do this (mainly for code clarity using method because sub feels...misleading)?
With regards to being misleading: the FETCH and STORE values expecte Callables, which could be either a method or a sub.
Getting back to the question, there is no direct way of doing this, but there is a better indirect way that may be clearer. You can do this by setting up the multi sub first, and then passing the proto as the parameter:
proto sub store(|) {*}
multi sub store(\self, Int) { say "Int" }
multi sub store(\self, Str) { say "Str" }
my $a := Proxy.new(
FETCH => -> $ { 42 },
STORE => &store,
);
say $a; # 42
$a = 42; # Int
$a = "foo"; # Str
And if you want to make the code shorter, but possibly less understandable, you can get rid of the proto (because it will be auto-generated for you) and the sub in the multi (because you can):
multi store(\self, Int) { say "Int" }
multi store(\self, Str) { say "Str" }
my $a := Proxy.new(
FETCH => -> $ { 42 },
STORE => &store,
);
say $a; # 42
$a = 42; # Int
$a = "foo"; # Str

Concurrency, react-ing to more than one supply at a time

Please consider the code below. Why is the output of this is "BABABA" and not "AAABAA" / "AABAAAB"? Shouldn't the two supplies run in parallel and the whenever fire immedeatly when there is an event in any of them?
my $i = 0;
my $supply1 = supply { loop { await Promise.in(3); done if $i++> 5; emit("B"); } };
my $supply2 = supply { loop { await Promise.in(1); done if $i++> 5; emit("A"); } };
react
{
#whenever Supply.merge($supply1, $supply2) -> $x { $x.print }
whenever $supply1 -> $x { $x.print };
whenever $supply2 -> $x { $x.print };
}
When we subscribe to a supply block, the body of that supply block is run immediately in order to set up subscriptions. There's no concurrency introduced as part of this; if we want that, we need to ask for it.
The best solution depends on how close the example is to what you're doing. If it's very close - and you want to emit values every time interval - then the solution is to use Supply.interval instead:
my $i = 0;
my $supply1 = supply { whenever Supply.interval(3, 3) { done if $i++ > 5; emit("B"); } };
my $supply2 = supply { whenever Supply.interval(1, 1) { done if $i++> 5; emit("A"); } };
react {
whenever $supply1 -> $x { $x.print };
whenever $supply2 -> $x { $x.print };
}
Which simply sets up a subscription and gets out of the setup, and so gives the output you want, however you do have a data race on the $i.
The more general pattern is to just do anything that gets the loop happening out of the setup step. For example, we could use an a kept Promise to just "thunk" it:
my constant READY = Promise.kept;
my $i = 0;
my $supply1 = supply whenever READY {
loop { await Promise.in(3); done if $i++> 5; emit("B"); }
}
my $supply2 = supply whenever READY {
loop { await Promise.in(1); done if $i++> 5; emit("A"); }
}
react {
whenever $supply1 -> $x { $x.print };
whenever $supply2 -> $x { $x.print };
}
Which helps because the result of a Promise will be delivered to the supply block via the thread pool scheduler, thus forcing the execution of the content of the whenever - containing the loop - into its own scheduled task.
This isn't especially pretty, but if we define a function to do it:
sub asynchronize(Supply $s) {
supply whenever Promise.kept {
whenever $s { .emit }
}
}
Then the original program only needs the addition of two calls to it:
my $i = 0;
my $supply1 = supply { loop { await Promise.in(3); done if $i++> 5; emit("B") } }
my $supply2 = supply { loop { await Promise.in(1); done if $i++> 5; emit("A") } }
react {
whenever asynchronize $supply1 -> $x { $x.print }
whenever asynchronize $supply2 -> $x { $x.print }
}
To make it work as desired. Arguably, something like this should be provided as a built-in.
It is possible to use a Channel as well, as the other solution proposes, and depending on the problem at hand that may be suitable; the question is a bit too abstracted from a real problem for me to say. This solution stays within the Supply paradigm, and is neater in that sense.
Thanks to jjmerelo here, I managed to get it working. The channel was the right track, but you actually have to consume the channels supply.
use v6;
my Channel $c .= new;
my $supply1 = start { loop { await Promise.in(1); $c.send("B"); } };
my $supply2 = start { loop { await Promise.in(0.5); $c.send("A"); } };
react
{
whenever $c.Supply -> $x { $x.print };
}
$c.close;
Additional question: How good does that scale? Can you have several thousand supplies sending to the channel?
Supplies are asynchronous, not concurrent. You will need to use channels instead of supplies to feed them concurrently.
use v6;
my $i = 0;
my Channel $c .= new;
my $supply1 = start { for ^5 { await Promise.in(1); $c.send("B"); } };
my $supply2 = start { for ^5 { await Promise.in(0.5); $c.send("A"); } };
await $supply2;
await $supply1;
$c.close;
.say for $c.list;
In this case, the two threads start at the same time, and instead of using .emit, then .send to the channel. In your example, they are effectively blocked while they wait, since they are both running in the same thread. They only give control to the other supply after the promise is kept, so that they run apparently "in parallel" and as slow as the slower of them.
Ok, so here is my real code. It seems to work, but I think there is a race condition somewhere. Here's some typical (albeit short) output.
A monster hatched.
A monster hatched.
A hero was born.
The Monster is at 2,3
The Monster is at 3,2
The Player is at 0,0
The Monster (2) attacks the Player (3)
The Monster rolls 14
The Player rolls 4
The Monster inflicts 4 damage
The Player (3) attacks the Monster (2)
The Player rolls 11
The Monster rolls 8
The Player inflicts 45 damage
The Monster is dead
The Monster is at -3,-3
The Player is at 4,-3
The Monster (1) attacks the Player (3)
The Monster rolls 8
The Player rolls 5
The Monster inflicts 11 damage
The Player has 32 hitpoints left
The Monster is at -4,1
The Player is at -1,4
The Player (3) attacks the Monster (1)
The Player rolls 12
The Monster rolls 11
The Player inflicts 46 damage
The Monster is dead
Stopping
Game over. The Player has won
Now the strange thing is, sometimes, in maybe 20% of the runs, the last line of the output is
Game over. The GameObject has won
as if the object got caught while it already is partially deconstructed? Or something? Anyway here's the code.
class GameObject
{
has Int $.id;
has Int $.x is rw;
has Int $.y is rw;
has $.game;
has Int $.speed; #the higher the faster
has Bool $.stopped is rw;
multi method start( &action )
{
start {
loop {
&action();
last if self.stopped;
await Promise.in( 1 / self.speed );
}
$.game.remove-object( self );
}
}
method speed {
$!speed +
# 33% variation from the base speed in either direction
( -($!speed / 3).Int .. ($!speed / 3).Int ).pick
;
}
}
role UnnecessaryViolence
{
has $.damage;
has $.hitpoints is rw;
has $.offense;
has $.defense;
method attack ( GameObject $target )
{
say "The {self.WHAT.perl} ({self.id}) attacks the {$target.WHAT.perl} ({$target.id})";
my $attacker = roll( $.offense, 1 .. 6 ).sum;
say "The {self.WHAT.perl} rolls $attacker";
my $defender = roll( $target.defense, 1 .. 6 ).sum;
say "The {$target.WHAT.perl} rolls $defender";
if $attacker > $defender
{
my $damage = ( 1 .. $.damage ).pick;
say "The {self.WHAT.perl} inflicts {$damage} damage";
$target.hitpoints -= $damage ;
}
if $target.hitpoints < 0
{
say "The {$target.WHAT.perl} is dead";
$target.stopped = True;
}
else
{
say "The {$target.WHAT.perl} has { $target.hitpoints } hitpoints left";
}
}
}
class Player is GameObject does UnnecessaryViolence
{
has $.name;
multi method start
{
say "A hero was born.";
self.start({
# say "The hero is moving";
# keyboard logic here, in the meantime random movement
$.game.channel.send( { object => self, x => (-1 .. 1).pick, y => (-1 .. 1).pick } );
});
}
}
class Monster is GameObject does UnnecessaryViolence
{
has $.species;
multi method start
{
say "A monster hatched.";
self.start({
# say "The monster {self.id} is moving";
# AI logic here, in the meantime random movement
$.game.channel.send( { object => self, x => (-1 .. 1).pick, y => (-1 .. 1).pick } );
});
}
}
class Game
{
my $idc = 0;
has GameObject #.objects is rw;
has Channel $.channel = .new;
method run{
self.setup;
self.mainloop;
}
method setup
{
self.add-object( Monster.new( :id(++$idc), :species("Troll"), :hitpoints(20), :damage(14), :offense(3), :speed(300), :defense(3), :x(3), :y(2), :game(self) ) );
self.add-object( Monster.new( :id(++$idc), :species("Troll"), :hitpoints(10), :damage(16), :offense(3), :speed(400), :defense(3), :x(3), :y(2), :game(self) ) );
self.add-object( Player.new( :id(++$idc), :name("Holli"), :hitpoints(50), :damage(60), :offense(3), :speed(200) :defense(2), :x(0), :y(0), :game(self) ) );
}
method add-object( GameObject $object )
{
#!objects.push( $object );
$object.start;
}
method remove-object( GameObject $object )
{
#!objects = #!objects.grep({ !($_ === $object) });
}
method mainloop
{
react {
whenever $.channel.Supply -> $event
{
self.stop-game
if self.all-objects-stopped;
self.process-movement( $event );
self.stop-objects
if self.game-is-over;
};
whenever Supply.interval(1) {
self.render;
}
}
}
method process-movement( $event )
{
#say "The {$event<object>.WHAT.perl} moves.";
given $event<object>
{
my $to-x = .x + $event<x>;
my $to-y = .y + $event<y>;
for #!objects -> $object
{
# we don't care abour ourselves
next
if $_ === $object;
# see if anything is where we want to be
if ( $to-x == $object.x && $to-y == $object.y )
{
# can't move, blocked by friendly
return
if $object.WHAT eqv .WHAT;
# we found a monster
.attack( $object );
last;
}
}
# -5 -1 5
# we won the fight or the place is empty
# so let's move
.x = $to-x == 5 ?? -4 !!
$to-x == -5 ?? 4 !!
$to-x;
.y = $to-y == 5 ?? -4 !!
$to-y == -5 ?? 4 !!
$to-y;
}
}
method render
{
for #!objects -> $object {
"The {$object.WHAT.perl} is at {$object.x},{$object.y}".say;
}
}
method stop-objects
{
say "Stopping";
for #!objects -> $object {
$object.stopped = True;
}
}
method stop-game {
"Game over. The {#!objects[0].WHAT.perl} has won".say;
$.channel.close;
done;
}
method game-is-over {
return (#!objects.map({.WHAT})).unique.elems == 1;
}
method all-objects-stopped {
(#!objects.grep({!.stopped})).elems == 0;
}
}
Game.new.run;

add a object to a array in my class

I want to add an object (from a different class) to an array in my class.
When I try to do that I get this
error: 0xC0000005: Access violation writing location
0x0000000000000000
I create the object (to be added) in the main function and I use the push method in the main function to add this object to my Parking_Lot class.
My code:
void Parking_Lot::push(Cars const &car)
{
time_t t = time(NULL);
struct tm Today = *localtime(&t);
if (is_full())
{
printf("Parking lot is full!!\n");
return;
}
if (Today.tm_hour < OpeningT.tm_hour && Today.tm_hour > ClosingT.tm_hour)
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
else if (Today.tm_hour == OpeningT.tm_hour || Today.tm_hour == ClosingT.tm_hour)
{
if(Today.tm_min > OpeningT.tm_min || Today.tm_min < ClosingT.tm_min) Lot[front++] = car;
else
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
}
else if(Today.tm_hour > OpeningT.tm_hour && Today.tm_hour < ClosingT.tm_hour) Lot[front++] = car;
}
where the car is the object I want to add and the Lot is the array in my class that I want to add the object to.
The constructor of my class:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
What am i doing wrong here and how can I fix it?
The problem is in your constructor:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
You define a new and separate variable Lot inside the constructor. It will not be related to any possible member variable you might have with the same name.
You need to initialize the member variable instead:
Parking_Lot::Parking_Lot(int s)
{
Lot = new Cars[s+1];
size = s;
front = 0;
}

Array allocate in function

I ve got a problem with allocating cli::array in function.
I have this kind of object:
array<double>^ tmsr2;
now I want to allocate it in function so:
void allocate(array<double>^ tmsr2)
{
tmsr2=gcnew array<double>(100);
}
Now, tmsr2 in function gets allocated well but I lose the pointer when returning to main()
The problem is clear to me, just like if I want to allocate simple array "double *a"; I need to pass pointer to function so "&a" and then everything works fine. I just don't know the syntax with managed arrays. Help much appreciated.
Peter
Since array<double> is a managed type, you can use a managed tracking reference here, instead of a plain reference.
void allocate(array<double>^% tmsr2)
{
tmsr2 = gcnew array<double>(100);
}
Here's my test app:
public ref class AsAClassField
{
public:
array<double>^ b;
AsAClassField()
{
allocate(b);
Debug::WriteLine("b = " + (b != nullptr ? "array" : "null"));
}
};
int main(array<System::String ^> ^args)
{
array<double>^ a = nullptr;
allocate(a);
Debug::WriteLine("a = " + (a != nullptr ? "array" : "null"));
AsAClassField^ foo = gcnew AsAClassField();
return 0;
}
Output:
a = array
b = array
Of course, you could always switch your allocate function to return the newly allocated array, rather than taking it as a reference. That would be more in the managed style.
You can pass the array as a reference:
void allocate(array<double>^ &tmsr2)
{
tmsr2=gcnew array<double>(100);
}