A constructor with only 1 argument in Perl 6 - raku

I want to override new so that my class can be created only by passing one argument to the constructor, no more and no fewer.
class MyClass {
has $.var1;
method new($var1) {
return MyClass.new(var1 => $var1);
}
}
my $my_class1 = MyClass.new(33);
say $my_class1.var1;
The error is:
Too few positionals passed; expected 2 arguments but got 1
in method new at test1.pl6:28
in method new at test1.pl6:28
in block <unit> at test1.pl6:33
What's up with it?

Custom constructors need to call bless, ie
class MyClass {
has $.var1;
method new($var1) {
return self.bless(var1 => $var1);
}
}
There are a few things that can be improved, eg
one could add an explicit invocant parameter and use :U to make .new() fail when called on instance objects
the explicit return is superfluous - the last expression within the method will be returned anyway, and currently, it actually hurts performance
there's syntactic sugar for passing a named argument held in a variable of the same name
Putting it all together, we end up with
class MyClass {
has $.var1;
method new(MyClass:U: $var1) {
self.bless(:$var1);
}
}
As to where your error comes from:
Your method new is declared to take a positional argument (giving a total count of 2 expected arguments due to the implicit invocant), but the call MyClass.new(var1 => $var1) only passed a named one. Note that said method is the only .new() present in your class, so if the call had actually worked, you would have ended up with infinite recursion!

Related

When does init block of object get called?

I tried to know when the init block of object gets called in Kotlin using the below code, but I don't get any result in the console:
fun main(args: Array<String>) {
TestObj
TestObj
}
object TestObj {
var count = 0
init {
fun howManyTimes() {
println(++count)
}
}
}
Dimitri's answer is correct for your problem, however the correct answer for your specific question is:
if it is a class instantiation, the init is executed before the constructor is called.
if it is an object, according to Kotlin documentation, it will be called whenever the (singleton) object is called first time, as static objects are lazy initialized.
You are not getting any output in console, because you are declaring function inside the init block, and not calling it.
Change TestObj code to:
object TestObj {
var count = 0
init {
howManyTimes()
}
fun howManyTimes() {
println(++count)
}
}
Above answer gives a clear explanation as to why you are not getting expected output, I would try to answer your question
When does init block of object get called?
From kotlin in action
The init keyword introduces an initializer block. Such blocks contain
initialization code that’s executed when the class is created, and are
intended to be used together with primary constructors. Because the
primary constructor has a constrained syntax, it can’t contain the
initialization code; that’s why you have initializer blocks. If you
want to, you can declare several initializer blocks in one class.

Using public and private methods inside their class in Perl 6

If I have a public method, I can call it inside its class using both $.name and self.name:
class TEST {
has Int $.a;
method b($x) {
return $!a * $x;
}
method c($y) {
return self.b($y) * 3; # or $.b($y)
}
}
my $m = TEST.new(a => 10);
say $m.c(2); # 60
But if I make b a private method, I only can call it with self!b, not $!b, otherwise I get the following error message:
Attribute $!b not declared in class TEST
What's behind this rule? What are the rules of calling a method inside its own class?
An attribute can always be referred to as $!foo in a class. If you do that, than the code will be generated to directly access the attribute itself, and any classes subclassing your class will not be able to change this behaviour.
If you use has $.foo in the declaration of a class, it means that a public accessor (and if you add is rw it can also function as a mutator).
When you use $.foo in your code otherwise, it is exactly the same as $( self.foo ). This means that it will call the method foo on self, and itemize the return value (make it a single "thing" if it wasn't yet). This will go wrong if you defined your attribute with $!foo and you did not supply a method foo yourself.
This goes even further: $.bar really means self.bar: you only need to have a method existing by the name bar, which may not be related to any attribute at all.
If you define a private method !baz, the ! just indicates the privacy of the method, which means you need to call it indeed as self!baz. There is no short syntax for it.
Personally I dislike the fact that you can say $.zippo even if zippo is not an attribute. But I'm afraid that ship has sailed. But this behaviour is now causing you confusion :-(
So what's behind the rule for not having a short syntax for calling a private method? Not sure, I guess really that $!foo was already taken to mean direct access to the attribute, and provide you with a compile time error if the attribute doesn't exist.
Hope this answers your question!

Calling a class's method as default arg in constructor

I'm constructing a class and then trying to call a member method of that class as a default value for one of the constructor args.
Why isn't this valid Kotlin?
// unresolved reference: defaultText
class MyThing(val text: String = defaultText()) {
fun defaultText() = "hi"
}
It's possible using two separate constructors in both Java and Kotlin, but then I lose the conciseness of default args.
class MyThing {
private val text: String
constructor(text: String) {
this.text = text
}
constructor() {
this.text = defaultText()
}
private fun defaultText(): String {
return "hi"
}
}
The biggest problem of having a constructor's default parameter expression call a member function of the same instance is that the default arguments are evaluated before the constructor is called.
Given that, such a member function would have to run on a completely un-initialized instance of the class (because even the super constructors will work after that, see this answer about the execution order).
Usually, member functions perform some logic taking the instance state into account, and having a member function run on an empty instance might break some of that logic (e.g. all fields will hold nulls, even the backing fields of Kotlin not-null properties). Overall, even when such calls do not fail at runtime, they are likely introduce subtle bugs, so using a completely uninitialized instance is prohibited.
With regard to the secondary constructor, well, at least it runs after the super constructor initializes some part of the instance, which is thus not completely empty, but it's up to you to make sure you don't use the parts of the class that are not initialized (if you do, you may again encounter a runtime failure or introduce a bug).
I'd rather suggest using a function of a companion object (those are initialized before the class is first used) for this purpose:
class MyThing(val text: String = defaultText()) {
companion object {
fun defaultText() = "hi"
}
}
Or even a top-level function:
fun defaultText() = "hi"
class MyThing(val text: String = defaultText())

Why can't I call meta methods on Routine::WrapHandle?

This is a continuing question from my previous one Why is Perl 6's unwrap method a method of Routine?, but mostly unrelated.
The wrap method is documented to return "an instance of a private class called WrapHandle. Besides that being odd for leaking a class that's private, it's not actually the name of the thing that comes back. The class is actually Routine::WrapHandle:
$ perl6
> sub f() { say 'f was called' }
sub f () { #`(Sub|140397740886648) ... }
> my $wrap-handle = &f.wrap({ say 'before'; callsame; say 'after' });
Routine::WrapHandle.new
But here's the question. I wanted to call .^methods on Routine::WrapHandle. That doesn't work:
> Routine::WrapHandle.^methods
Could not find symbol '&WrapHandle'
in block <unit> at <unknown file> line 1
This is the same as trying it on an undefined class name:
> Foo::Baz.^methods
Could not find symbol '&Baz'
in block <unit> at <unknown file> line 1
I can call meta methods on the instance though:
> $wrap-handle.^methods
(restore)
> $wrap-handle.^name
Routine::WrapHandle
What's going on there?
The definition of Routine::WrapHandle looks something like this:
my class Routine {
method wrap(&wrapper) {
my class WrapHandle { ... }
...
}
}
We can ignore the surrounding method; the important bit is that we're dealing with a lexical inner class defined within an outer class. Simplifying some more, we arrive at the following pattern:
package Foo {
my class Bar {}
say Bar.^name; #=> Foo::Bar
}
say try Foo::Bar; #=> Nil
The fully qualified name of the inner class will include the name of the enclosing package, but due to the explicit my (instead of the implicit our), the class will not be installed as a package variable and the lookup at file scope fails.

How are overridden properties handled in init blocks?

I'm trying to understand why the following code throws:
open class Base(open val input: String) {
lateinit var derived: String
init {
derived = input.toUpperCase() // throws!
}
}
class Sub(override val input: String) : Base(input)
When invoking this code like this:
println(Sub("test").derived)
it throws an exception, because at the time toUpperCase is called, input resolves to null. I find this counter intuitive: I pass a non-null value to the primary constructor, yet in the init block of the super class it resolves to null?
I think I have a vague idea of what might be going on: since input serves both as a constructor argument as well as a property, the assignment internally calls this.input, but this isn't fully initialized yet. It's really odd: in the IntelliJ debugger, input resolves normally (to the value "test"), but as soon as I invoke the expression evaluation window and inspect input manually, it's suddenly null.
Assuming this is expected behavior, what do you recommend to do instead, i.e. when one needs to initialize fields derived from properties of the same class?
UPDATE:
I've posted two even more concise code snippets that illustrate where the confusion stems from:
https://gist.github.com/mttkay/9fbb0ddf72f471465afc
https://gist.github.com/mttkay/5dc9bde1006b70e1e8ba
The original example is equivalent to the following Java program:
class Base {
private String input;
private String derived;
Base(String input) {
this.input = input;
this.derived = getInput().toUpperCase(); // Initializes derived by calling an overridden method
}
public String getInput() {
return input;
}
}
class Derived extends Base {
private String input;
public Derived(String input) {
super(input); // Calls the superclass constructor, which tries to initialize derived
this.input = input; // Initializes the subclass field
}
#Override
public String getInput() {
return input; // Returns the value of the subclass field
}
}
The getInput() method is overridden in the Sub class, so the code calls Sub.getInput(). At this time, the constructor of the Sub class has not executed, so the backing field holding the value of Sub.input is still null. This is not a bug in Kotlin; you can easily run into the same problem in pure Java code.
The fix is to not override the property. (I've seen your comment, but this doesn't really explain why you think you need to override it.)
The confusion comes from the fact that you created two storages for the input value (fields in JVM). One is in base class, one in derived. When you are reading input value in base class, it calls virtual getInput method under the hood. getInput is overridden in derived class to return its own stored value, which is not initialised before base constructor is called. This is typical "virtual call in constructor" problem.
If you change derived class to actually use property of super type, everything is fine again.
class Sub(input: String) : Base(input) {
override val input : String
get() = super.input
}