in reply to Re: Raku classes: syntax question
in thread Raku classes: syntax question

:$x and :$y declare named parameters

I looked up "named parameters", and it turns out the syntax used for the parameters in the set method:

method set( :$x = $.x, :$y = $.y )

is the same syntax used for any function:

Named parameters In contrast to positional parameters, named parameters are referred by their names. The following function takes two parameters called $from and $to: sub distance(:$from, :$to) { $from - $to } Now, to call the function, you need to name the arguments: say distance(from => 30, to => 10); # 20 It is an error to pass the arguments as if they were positional. For example, a call distance(30, 10) generates an error: ...

See: named parameters

I found some basic information on the syntax used in classes here:

class Rectangle { has Int $.length = 1; has Int $.width = 1; method area(--> Int) { return $!length * $!width; } } my $r1 = Rectangle.new(length => 2, width => 3); say $r1.area();

We define a new Rectangle class using the class keyword. It has two attributes, $!length and $!width introduced with the has keyword. Both default to 1. Read only accessor methods are automatically generated. It is rarely necessary to explicitly write a constructor. An automatically inherited default constructor called new will automatically initialize attributes from named parameters passed to the constructor.

'Attributes" (called fields or instance storage in other languages) are never directly accessible from outside of the class (this is in contrast to many other languages). This encapsulation is one of the key principles of object oriented design. The ! twigil (Ed. twigil = secondary sigil) emphasizes that this attribute is private to the class. The attribute is encapsulated. Private attributes will not be set by the default constructor by default...

And this:

has Bool $.done;

This scalar attribute (with the $ sigil) has a type of Bool. Instead of the ! twigil, the . twigil is used. While Raku does enforce encapsulation on attributes, it also saves you from writing accessor methods. Replacing the ! with a . both declares a private attribute and an accessor method named after the attribute. In this case, both the attribute $!done and the accessor method done are declared. It's as if you had written:

has Bool $!done; method done() { return $!done }

Note that this is not like declaring a public attribute, as some languages allow; you really get both a private attribute and a method, without having to write the method by hand. You are free instead to write your own accessor method, if at some future point you need to do something more complex than returning the value.

So I would prefer to declare the set method as method set( :$x = $!x, :$y = $!y ). But, of course, YMMV.

Yes, that makes more sense to me. The variable's name is $!x (where the ! indicates it is a private variable) and as far as I know you only write $.x when you declare the instance variable in order to generate a read accessor.

Here is an example I played with:

use v6; class Point { has $.x = 0; has $.y = 0; method gist { "[$.x, $.y]" } method set( :$joe = $!x, :$susan = $!y ) { $!x = $joe; $!y = $susan; } } my $point = Point.new(); say $point.x; # 0 say $point; # [0, 0] # $point.x = 3; Error! $point = Point.new(x => 3, y => 5); say $point; # [3,5] $point.set(joe => 10, susan => 20); say $point; # [10, 20] $point.set(joe => 100); say $point; # [100, 20]

Thanks for taking the time to help me. I really appreciate it.

Replies are listed 'Best First'.
Re^3: Raku classes: syntax question
by p6steve (Sexton) on Feb 05, 2024 at 19:53 UTC

    That's a good question and a good answer. Raku (like perl) has some niceties as you dig in ... but the defaults are set at "easy"

    Consider this...

    use v6; class Point { has $.x is rw = 0; has $.y is rw = 0; method gist { "[$.x, $.y]" } method set( :$joe = $.x, :$susan = $.y ) { #method set( :$joe = $!x, :$susan = $!y ) { $.x = $joe; $.y = $susan; } } class Pixel is Point { has Int $.x is rw = 0; has Int $.y is rw = 0; has $.color = '#000000'; } my $point = Pixel.new(); #my $point = Point.new(); say $point.x; # 0 say $point; # [0, 0] # $point.x = 3; Error! $point = Pixel.new(x => 3, y => 5); #$point = Point.new(x => 3, y => 5); say $point; # [3,5] $point.set(joe => 10, susan => 20); say $point; # [10, 20] $point.set(joe => 100); say $point; # [100, 20]

    The $!x / $!y variant does not work because it directly refers to the PRIVATE ATTR of the Point class. But, in this case, we have used inheritance to override the Point x/y with Pixel x/y. So, when you need to reach for inheritance then the $.x / $.y variants help ... since they are the same as saying self.x and self.y - ie. they route via the settor / getter METHODS.

    We need the 'is rw' to ask raku to make a settor method so that $.x = $joe; $.y = $susan; can use the assignment operation to set attr values

      ...fwiw I would do this
      use v6; class Point { has $.x is rw = 0; has $.y is rw = 0; method gist { "[$.x, $.y]" } method set(:$x, :$y) { $.x = $x with $x; $.y = $y with $y; } } class Pixel is Point { has Int $.x is rw = 0; has Int $.y is rw = 0; has $.color = '#000000'; } my $point = Pixel.new(); say $point.x; # 0 say $point; # [0, 0] $point.x = 3; # Works now! $point = Pixel.new( :x(3), :y(5) ); say $point; # [3,5] $point.set( :x(10), :y(20) ); say $point; # [10, 20] $point.set( :x(100) ); say $point; # [100, 20]