Archive
Trust issues
On IRC japhb told us that he needs a class to trust another class that can’t see the to be trusted class.
class B {…}
class A {
trusts B;
}
class B {
}
This is nice and simple and allows B to call private methods on A. Sadly, that only works if A
and B
reside in the same file because a forward declaration will cause a compile time error, unless we define the declared type in the same compilation unit.
Method resolution is a runtime creature in Raku. By carefully looking at the code, we can learn where Rakudo stores what we need to cheat with.
class A {
has $!a = 'private';
method !a { $!a }
}
multi sub trait_mod:<is>(Mu:U \obj, :$spying!) {
A.^add_trustee(obj);
}
class B is spying(A) {
has A $.a = A.new;
method m { say $!a!A::a }
}
B.new.m;
Luckily, the trait is
operates quite early at compile time, so we don’t mess up method dispatch. I’m not feeling to bad poking with a trait where I should not peek. We can always move quickly into NQP-land and break things.
method cheating {
use nqp;
say nqp::getattr($.a, A, 'a');
}
As shown above, privacy is a matter of politeness. What leaves the question, if forcing a forward declaration to be resolved locally, to be a good design decision. I shall ponder to file a problem solving issue.
That meant war
I try to avoid to allow politics or current events to seep into my blog. The topic is the 100 year language and as such wont be history. Sadly, the head-oligarch has publicly given obvious bullshit-reasons to invade a neighbouring country. I would like to use the powers of …
to shed some light into the current darkness.
The official numbers (read: favouringly rounded up) for the population of Russia is 145805947 people. If only they could get themselves a decent government, that could have been quite a few hugs. But hugging they ain’t do enough, resulting in a birthrate of 1.82 children per woman. Let’s write that down.
my $woman = 145_805_947 / 2;
my $girls-per-woman := 0.91;
role Degression { }
my \degression = (2022, $woman), -> [$y, $w] { ($y + 35, $w * $girls-per-woman) but Degression } … ∞;
multi sub pretty(Degression [$year, $woman]) {
"year: $year, Russians in RU: {$woman * 2}"
}
say degression[1000/35].&pretty;
# year: 3002, Russians in RU: 10397626.7
say "Soldiers available in {(1000/35).Int} generations: {Int(degression[1000/35][1]/$woman * 140000)}";
# Soldiers available in 28 generations: 9983
Here, I use an empty role
to mark each value in the lazy list. Since I start with a 2-element list, I have to use destructuring and return a list in the generator function. The role
allows for multi dispatch and other type checks, as shown in sub pretty
.
Russia tries to build up independent industry for more then 10 years. That doesn’t work with a negative population growth. So they utterly depend on immigration from former soviet countries. They also depend on those counties to carry the financial burden to teaching the Russian language. Ukraine wants to join the EU in hopes to repeat the success of the Czechs (Hi Jonathan!) and Polsky (lol, Brexit!) to return to their spiritual home and grow the economy of their ancestors.
If you want to avoid future wars, don’t go to Russia. No people, no soldiers, no war. Also, being paid in ₽ may not be the most solid plan.
Self-referring labels
Lizmat kindly allowed Label
to expose its file and line-number. That is handy if we want to convey messages about the code itself, without having to worry about edits invalidating our line-numbers. The first use case that came to mind are lightweight singletons that are easy to find.
barcode: Nil;
qrcode: Nil;
say [barcode ~~ qrcode, barcode === qrcode, barcode =:= qrcode]; # [False False False]
put barcode; # barcode ../label-introspection.raku:16
This might be handy when sending messages through a Channel
.
my $ch = Channel.new;
start {
HERE: Nil;
THERE: Nil;
$ch.send(.item) for ((1, 2, HERE, THERE) xx ∞).flat;
}
.put for @$ch;
# OUTPUT: 1
# 2
# HERE ../label-introspection.raku:24
# THERE ../label-introspection.raku:25
# …
If those signals end up in a Str
unintended, we have a good chance to find the source of the error, even when we have to look at the sender-end of a Channel
.
We can also create error messages that point to a different line then a stacktrace might.
sub may-return-nil { }
ENIL: my $var is default(Failure.new(ENIL)) = may-return-nil;
say $var;
EWHOOPSY: fail(EWHOOPSY);
CATCH {
when X::AdHoc && .payload ~~ Label {
put "WELP! I encountered {.name} in {.file}:{.line}" with .payload;
}
}
POD doesn’t allow us to do compile time interpolation (yet). Since it is made up of Array
s, we can cheat.
DOCLABEL: sub described {
}
=begin pod
Sub described is defined in L<PLACEHOLDER>.
=end pod
CHECK $=pod[0].contents[0].contents[1] = DOCLABEL.&{.file ~ ':' ~ .line};
say $=pod;
# OUTPUT: [Pod::Block::Named{:name("pod")}
# Pod::Block::Para
# Sub described is defined in
# ../label-introspection.raku:31
# .
# ]
There are quite a few things hidden in CORE and I don’t like to use nqp::attr
to get hold of them. A public interface is better then an accidental one. The former make way better idioms.
Pushing …
Thanks to ∖
, PWC 154 part 1 is so boring, I’m not going into details. Part two however is a bit of a head scratcher. We are asked to implement a sequence with the properties:
P(0) = P(1) = P(2) = 1
P(n) = P(n-2) + P(n-3)
Using the sequence operator requires a trick thought.
my \padovan = 1, 1, 1, * + * + 0 * * … ∞;
my \padovan-prime = padovan.grep(*.is-prime).unique;
I have to convince it to operate on the 1th and 2nd element of the initial list and then advance by one. For once, math is on my side because with 0 * *
I can force a 3rd automatic variable into existence, without having it take part in building the sum. The rest is just filtering out anything that isn’t prime.
There is another way to skip arguments if we are willing to use a pointy-block.
my \padovan = 1, 1, 1, -> $a, $b, $ { $a + $b } … ∞;
This is not as clever but looks intentional. It’s probably better that way.