How to correctly augment Any? - raku

The following program:
use v6.c;
use MONKEY-TYPING;
augment class Any {
method show0 { self.say }}
augment class List {
method show1 { self.say }}
<hello world>.show0;
<hello world>.show1;
produces the expected output of:
(hello world)
(hello world)
While this one:
use v6.c;
use MONKEY-TYPING;
augment class Any {
method show0 { self.say }}
<hello world>.show0;
produces an error:
No such method 'show0' for invocant of type 'List'. Did you mean 'show0'?
in block <unit> at showcase.p6 line 9
Is that a bug or am I just holding it wrong?

First of all: augmenting core classes, at least in the foreseeable future of Rakudo Perl 6, is not a good idea. It doesn't play well with precompilation.
Secondly: when a class is a subclass of another class, the subclass "knows" from which it inherits. Alas, this doesn't work the other way around: a class does not know of its subclasses (at least at the moment of this writing).
This means that if you augment Any, none of its subclasses know that should also re-compose themselves. In your first example, you do that with the List class by augmenting that. However, if you would reverse the order of the augments, it wouldn't work either, because the List class would get re-composed before the Any class would get re-composed.
It's therefore that it's recommended to mix any extra methods using roles, either into a class, or into an object (mixins of roles)

A summary of the various comments here and on the issue I created on Github:
As Liz mentioned currently the children types do not see augmentations of their parents. This is true unless there was a flush of the method cache for that type.
This behaviour is a known limitation that will be fixed some time in the future with low priority.
Reconstructing the class with .^compose can be used to make augmented methods known to the children:
use v6.c;
use MONKEY-TYPING;
augment class Any {
method show0 { self.say }}
List.^compose;
<hello world>.show0; # OUTPUT: (hello world)
Alternatively the qualified class can be accessed directly:
use v6.c;
use MONKEY-TYPING;
augment class Any {
method show0 { self.say }}
<hello world>.Any::show0; # OUTPUT: (hello world)

Related

Why does `BUILD` not see attribute from parent class?

class A { has $.name; };
class B is A { submethod BUILD { $!name = 'foo' } };
This code looks natural but throws error.
Attribute $!name not declared in class B
Yes, it is not declared in class B, but we are in the partially constructed object during B::BUILD and documentation says that bless creates the new object, and then walks all subclasses in reverse method resolution order. So $!name attribute should be known for class B in this phase, right?
Is there any way to set parent class attributes during object construction without using new method? I know that new will do the trick here, but BUILD has a lot of syntactic sugar and BUILD / TWEAK feel more DWIMy and straightforward than resolving to low-level blessing in new.
Private attribute syntax ($!foo) is only available for attributes that are lexically visible. That's why they're private :-)
If class A would want other classes be able to change, it would need to provide a mutator method explicitely or implicitely (with is rw).
Or you could let class A trust class B as described at https://docs.raku.org/routine/trusts#(Type_system)_trait_trusts .
Still it feels you would do better using roles:
role A {
has $.name is rw;
}
class B does A {
submethod BUILD { $!name = 'foo' }
}
The other option is to use the is built trait on attributes that you would like the default constructor to initialize.
Consider the following:
class A {
has $.name is built
}
class B is A { }
B.new(name => "Foo").gist.say; # B.new(name => "Foo")
This allows descendend classes to use the named parameter matching the attribute in .new to initialize the value at object creation time. Please note that this will work whether the attribute is public "$." or private "$!".
Hope that helps!
TL;DR All attributes are technically private. This design is a good one. You could just call a method in A from B. There are, of course, other options too.
Why doesn't BUILD see parent class attributes?
Quoting Wikipedia Fragile base class page problem:
One possible solution is to make instance variables private to their defining class and force subclasses to use accessors to modify superclass states.¹
Hence, per Raku Attributes doc:
In Raku, all attributes are private, which means they can be accessed directly only by the class instance itself.
B can call a method in A
This code looks natural:
class A { has $.name }
class B is A { submethod BUILD { $!name = 'foo' } }
Quoting again from Raku doc section linked above:
While there is no such thing as a public (or even protected) attribute, there is a way to have accessor methods generated automatically: replace the ! twigil with the . twigil (the . should remind you of a method call).
Your code generates a $!name attribute (private to A) plus a public .name method. Any code that uses the A class can call its public methods.
Your code hasn't used the autogenerated accessor method. But it could have done so with a couple small changes:
class A { has $.name is rw } # Add `is rw`
class B is A { submethod BUILD { self.name = 'foo' } } # s/$!name/self.name/²
say B.new # B.new(name => "foo")
is rw makes the public .name accessor method a read/write one instead of the default read only one.
Not using is rw
As I now understand from your first comment below, an is rw accessor is disallowed given your requirements. You can achieve any effect that a class supports via its public interface.
Let's first consider a silly example so it's clear you can do anything that any methods can do. Using, say, self.name, in A or B, might actually run one or more methods in A that make a cup of tea and return 'oolong' rather than doing anything with A's $!name:
class A {
has $.name = 'fred'; # Autogenerates a `method name` unless it's defined.
method name { 'oolong' } # Defines a `method name` (so it isn't generated).
}
my \a = A.new;
say a; # A.new(name => "fred")
say a.name; # oolong
Conversely, if an A object changes its $!name, doing so might have no effect whatsoever on the name of the next cup of tea:
class A {
has $.name = 'fred';
method name { 'rooibos' } # ignores `$!name`
method rename { $!name = 'jane' }
}
my \a = A.new;
say a; # A.new(name => "fred")
a.rename;
say a.name; # rooibos
To recap, you can (albeit indirectly) do anything with private state of a class that that class allows via its public API.
For your scenario, perhaps the following would work?:
class A {
has $.name;
multi method name { $!name }
multi method name (\val) { once $!name = val }
}
class B is A {
submethod BUILD { self.name: 42 }
}
my \a = B.new;
say a; # B.new(name => 42)
say a.name; # 42
a.name: 99; # Does nothing
say a.name; # 42
Footnotes
¹ Continuing to quote solutions listed by Wikipedia:
A language could also make it so that subclasses can control which inherited methods are exposed publicly.
Raku allows this.
Another alternative solution could be to have an interface instead of superclass.
Raku also supports this (via roles).
² self.name works where $!name does not. $.name throws a different compiler error with an LTA error message. See Using %.foo in places throws, but changing it to self.foo works.
Sorry that my answer is late in the day, but I feel that your original question is very well pitched and would like to add my variation.
class A {
has $!name;
submethod BUILD( :$!name ) {}
multi method name { $!name }
multi method name(\v) { $!name := v }
method gist(::T:) { "{::T.^name}.new( name => $!name )" }
}
class B is A {
submethod BUILD( :$name ) { self.name: $name // 'foo' }
}
say B.new; #B.new( name => foo )
say A.new(name => 'bar'); #A.new( name => bar )
say B.new(name => 'baz'); #B.new( name => baz )
Raku OO tries to do two mutually incompatible things:
provide a deep OO (similar to C++ / Java)
provide a lightweight OO (similar to Python / Ruby)
This is done by having a core that does #1 and then adding some sugar to it to do #2. The core gives you stuff like encapsulation, multiple inheritance, delegation, trust relationships, role based composition, delegation, MOP, etc. The sugar is all the boilerplate that Raku gives you when you write $. instead of $! so that you can just throw together classes to be lightweight datatypes for loosely structured data.
Many of the answers here bring suggestions from mode #2, but I think that your needs are slightly too specific for that and so my answer tilts towards mode #1.
Some notes to elaborate why I think this is a good solution:
you state that you cannot use is rw - this avoids traits
with proper method accessors, you have control over initialization
BUILD() is not constrained by the public accessor phasing
no need to go to roles here (that's orthogonal)
And some drawbacks:
you have to write your own accessors
you have to write your own .gist method [used by say()]
It is attributed to Larry that "everyone wants the colon(:)". Well, he had the last say, and that the Raku method call syntax self.name: 'foo' echos assignment self.name= 'foo' is, in my view, no accident and meant to ease the mental switch from mode #2 to #1. ;-)
Does Raku succeed to reconcile the irreconcilable? - I think so ... but it does still leave an awkward gear shift.
EDITED to add submethod BUILD to class A
Thanks everyone for great discussion and solution suggestions. Unfortunately there is no simple solution and it became obvious once I understood how Raku constructs object instances.
class A {
has $.name is rw;
};
class B is A {
submethod BUILD {
self.A::name = 123; # accessor method is already here
}
};
B.new.name.say; # will print 123
So if inheritance is used Raku works from parent class to child class fully constructing each class along the way. A is constructed first, $.name param is initialized, public attribute accessor methods are installed. This A instance become available for B construction, but we are not in A build phase anymore. That initialization is finished. My code example shows what is happening with syntactic sugar removed.
The fact that
submethod BUILD {
self.name = 123;
}
is available in class B during BUILD phase does not mean that we (as class B) have this attribute still available for construction. We are only calling write method on already constructed class A. So self.name = 123 really means self.A::name = 123.
TL;DR: Attributes are not collected from parent classes and presented to BUILD in child class to be set at the same time. Parent classes are constructed sequentially and only their method interfaces are available in child BUILD submethod.
Therefore
class A {
has $.name; # no rw
};
class B is A {
submethod BUILD {
$!name = 123;
}
};
will not work because once we reach submethod BUILD in B class attribute $.name is already constructed and it is read only.
Solution for shallow inheritance:
Roles are the way to go.
role A {
has $.name;
};
class B does A {
submethod BUILD {
$!name = 123;
}
};
Roles are copied to class composing them, so class B sees this $.name param as their own and can initialize it. At the same time roles autopun to classes in Raku and standalone my $a = A.new( name => 123 ) can be used as a class.
However roles overdose can lead to orthogonal pattern issues.
Solution for deep inheritance:
There is none. You cannot have secure parent classes with read-only attribute behavior and initialize this attribute in child class builder, because at this moment parent class portion of self will be already constructed and attribute will be already read-only. Best you can do is to wrap attribute of parent class in private method (may be Proxy) and make it write-once this way.
Sad conclusion:
Raku needs improvement in this area. It is not convenient to use it for deep inheritance projects. Maybe new phaser is needed that will mash every attribute from parent classes in role-style and present them to BUILD at the same time. Or some auto-trust mechanism during BUILD. Or anything that will save user from introducing role inheritance and orthogonal role layout (this is doing stuff like class Cro::CompositeConnector does Cro::Connector when class Cro::Connector::Composite is Cro::Connector is really needed) to deep OO code because roles are not golden hammer that is suitable for every data domain.

How do I see if a class has an init block using reflection?

If I have a Kotlin class like the following:
data class Foo(
val count: AtomicInteger
) {
init {
count.incrementAndGet()
}
}
How do I determine that this class has an init block using reflection?
The init block does not appear in Foo::class.members and I can't see a way of determining it from Foo::class.constructors.
Is there any way to find out information about the init block using kotlin.reflect?
This information is not available after compilation.
Init blocks and property initializers on JVM are compiled into some mixture of constructors and/or field initializers. It’s up to the compiler how it wants to do this in an optimal way.
Answer courtesy of Tenfour04

How to make Perl 6 class final?

For example, I have such code:
class Foo {}
class Bar is Foo {}
While this action usefulness is arguable, is it possible to prohibit inheritance from Foo?
There's no built-in way in the Perl 6 language to prohibit inheritance of a class, and this was a deliberately taken design decision. It's also not clear one could achieve this even with meta-programming, since the act of inheritance is driven by the subclass, with the parent class having no say in the process.
It is, however, possible to mark individual methods as not being inherited, by declaring them as a submethod instead of a method.
class P {
submethod m() { say "not inherited" }
}
class C is P {
}
say ?P.can('m'); # True
say ?C.can('m'); # False

Inheriting private attributes in Perl 6

I can't find anything in the docs, but it seems that there is no access in a subclass to its superclass's private variables. Am I right?
class A {
has $!a;
}
class B is A {
has $.b;
method set_a($x) {
$!a = $x;
}
}
my $var = B.new();
$var.set_a(5);
say $var.a;
This gives an error message:
Attribute $!a not declared in class B
BTW where to read about Classes in the docs? I have only found a rather short section Classes and Objects.
In Perl 6, an attribute declared in a class is accessible only within that class. This means one can confidently refactor the state in the class without having to worry about any uses of that state outside of the class.
Subclasses do not receive any special access with regards to attributes. Some languages provide a protected modifier. This does not exist in Perl 6, by design. Either something is private to that class, or is exposed (like has $.a) to the outside world, since:
So far as that class is concerned, a subclass is part of the outside world.
Given the general advice is to "prefer composition over inheritance", it seems strange to privilege inheritance, or provide a mechanism that frustrates refactoring from inheritance to composition.
Attributes in a role, by contrast, are composed into the class, working as if they had been declared in the class itself. Therefore, an attribute from a composed role may be used in the class body. If looking to write re-usable pieces of functionality in an OO context, it's more typical to use roles and composition in Perl 6, not inheritance. Indeed, writing the original code as:
role A {
has $!a;
}
class B does A {
has $.b;
method set_a($x) {
$!a = $x;
}
method a() { $!a }
}
my $var = B.new();
$var.set_a(5);
say $var.a;
Works as desired.

'this' is not defined in this context

How can I solve the following case?
interface I
class A(i: I)
class C : I, A(this) // << --- 'this' is not defined in this context
In short, I want to pass the class instance to super class constructor.
Is it possible in Kotlin?
P.S.
All the answers are good and technically correct. But let's give a concrete example:
interface Pilot {
fun informAboutObstacle()
}
abstract class Car(private val pilot: Pilot) {
fun drive() {
while (true) {
// ....
if (haveObstacleDetected()) {
pilot.informAboutObstacle()
}
// ....
}
}
fun break() {
// stop the car
}
}
class AutopilotCar : Pilot, Car(this) { // For example, Tesla :)
override fun informAboutObstacle() {
break() // stop the car
}
}
This example don't look too contrived, and why can't I implement it with OOP-friendly language?
No, this is not possible on the JVM. this is only available after the super class has been initialized.
From
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.10.2.4
The instance initialization method (§2.9.1) for class myClass sees the new uninitialized object as its this argument in local variable 0. Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass.
So the bytecode instruction aload 0 to push this on the stack is forbidden before the super-class constructor is called. That's why it cannot be passed as an argument to the super-constructor.
Kotlin was born as a JVM language and aims for maximum interoperability with Java code and a minimum overhead of its language features. While Kotlin could have chosen to orchestrate object initialization in a different way, it would create problems in mixed Java-Kotlin class hierarchies and add significant overhead.
In the good tradition of OOP languages such as Java, C# or Swift, Kotlin doesn't allow you to leak the this reference before the call to superclass initialization has completed. In your special case you're just storing the reference, but in just a slightly different case the superclass code might try to use the received object, which at that point is still uninitialized.
As a specific example of why languages don't allow this, consider a case where A is a class from a library you use and this rule is not in effect. You pass this like you do and things work fine. Later you update the library to a newer version and it happens to add something as benign as i.toString() to its constructor. It has no idea it's actually calling an overridden method on itself. Your toString() implementation observes all its invariants broken, such as uninitialized vals.
This design suffers from other problems, not just the circular initialization dependency you are struggling with now. In a nutshell, the class A expects this:
But instead you create this:
The class A has a dependency on a collaborator object of type I. It doesn't expect itself as the collaborator. This may bring about all kinds of weird bugs. For example your C.toString() may delegate to super.toString() and A.toString() (A is the super of C) may call into I.toString(), resulting in a StackOverflowError.
I can't say from your question whether A is designed for extension, which would make the C : A part correct, but you should definitely disentangle A from I.